【问题标题】:Asp.Net WebApi Inheritance with a BaseController带有 BaseController 的 Asp.Net WebApi 继承
【发布时间】:2015-01-15 13:07:21
【问题描述】:

我目前正在努力让 WebApi 中的继承像我想要的那样工作。 也许你能指出我正确的方向?

我的目标是拥有一个通用的 WebApi 项目,它可以在多个其他 WebApi 项目中重复使用。

例如:我有一个可重用的 UserController,它可以处理多个网站的登录。现在我建立了一个新的网站并将 UserController 添加到新创建的项目中,这很简单。

但现在新网站的需求发生了变化,我需要重载 UserController 方法以反映这些变化,而无需修改通用控制器。

我想要实现的可以在下面的代码sn-p中看到(当然这不会编译,因为C#抱怨找不到合适的方法来重载。)

// This belongs to solution "GenericWebApi"

public class LoginRequest
{
    public string User { get; set; }
}

public class BaseApiController : ApiController
{
     [Route("login")]
    public virtual HttpResponseMessage Login(LoginRequest request) 
    {
        return new HttpResponseMessage();
    }
}


// This belongs to solution "CarWebsite"

public class CarWebsiteLoginRequest : LoginRequest
{
    public string Car { get; set; }
}

[RoutePrefix("api/users")]
public class CarWebsiteApiController : BaseApiController
{
    public override HttpResponseMessage Login(CarWebsiteLoginRequest request)
    {
        // Do some car specific login stuff
        return base.Login(request);
    }
}

我发现一个可行的解决方案是将“LoginRequest”和“CarWebsiteLoginRequest”替换为“dynamic”,但这感觉完全不对,ModelBinder 当然不会按预期工作。

你有什么想法可以解决这个问题吗?

提前致谢

【问题讨论】:

    标签: c# asp.net .net asp.net-web-api asp.net-web-api2


    【解决方案1】:

    您可以将BaseApiController 设为通用:

    public class BaseApiController<TLoginRequest> : ApiController
    where TLoginRequest : LoginRequest
    {
        [Route("login")]
        public virtual HttpResponseMessage Login(TLoginRequest request)
        {
            return new HttpResponseMessage();
        }
    }
    

    并让您的CarWebsiteApiController 使用CarWebsiteLoginRequest 作为通用参数:

    public class CarWebsiteApiController : BaseApiController<CarWebsiteLoginRequest>
    {
        public override HttpResponseMessage Login(CarWebsiteLoginRequest request)
        {
            // Do some car specific login stuff
            return base.Login(request);
        }
    }
    

    【讨论】:

    • 感谢您的建议,这似乎是一个不错的方法。但我的 BaseApiController 将有 > 10-15 个 WebApi 操作。所以我需要将它设为 BaseApiController。你知道其他方法吗?
    【解决方案2】:

    如果你拉出变量并在方法内部读取它更容易重载

        /// <summary>
    /// Notice name is not Controller.cs  This would expose this API if the name ended in controller
    /// </summary>
    public class GenericControllerApi : ApiController
    {
        protected JavaScriptSerializer JsonReader = new JavaScriptSerializer();
    
        [HttpPost]
        public virtual HttpResponseMessage Login()
        {
            string JsonRequest = Request.Content.ReadAsStringAsync().Result;
    
            LoginRequest JSONData = null;
            try
            {
                JSONData = (LoginRequest)JsonReader.Deserialize(JsonRequest, typeof(LoginRequest));
            }
            catch { }
    
            if (JSONData != null)
            {
                if (CommonUserCalls(JSONData.User))
                {
                    ShowUser UserReturn = new ShowUser();
                    UserReturn.UserName = "BaseUser";
                    return Request.CreateResponse(HttpStatusCode.OK, UserReturn);
                }
    
                return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid User");
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "ShowUser not provided");
            }
        }
    
        protected bool CommonUserCalls(string User)
        {
            if (User == "MyUser")
            {
                return true;
            }
            return false;
        }
    
        public class LoginRequest
        {
            public string User { get; set; }
        }
    
        protected class ShowUser
        {
            public string UserName { get; set; }
        }
    }
    
    public class CarController : GenericControllerApi
    {
        [HttpPost]
        public override HttpResponseMessage Login()
        {
            string JsonRequest = Request.Content.ReadAsStringAsync().Result;
    
            CarWebsiteLoginRequest JSONData = null;
            try
            {
                JSONData = (CarWebsiteLoginRequest)JsonReader.Deserialize(JsonRequest, typeof(CarWebsiteLoginRequest));
            }
            catch { }
    
            if (JSONData != null)
            {
                if (CommonUserCalls(JSONData.User))
                {
                    ShowUser UserReturn = new ShowUser();
                    UserReturn.UserName = "CarUser";
                    return Request.CreateResponse(HttpStatusCode.OK, UserReturn);
                }
    
                return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid User");
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "CarWebsiteLoginRequest not provided");
            }
        }
    
        public class CarWebsiteLoginRequest : LoginRequest
        {
            public string Car { get; set; }
        }
    }
    

    假设您正在读取/发送 JSON

    【讨论】:

    • 感谢您的建议。与使用“动态”(使用 JObject,例如用于序列化)相比,这似乎没有提供任何好处。此外,您的解决方案添加了很多重复的代码,似乎不再使用通用控制器了。
    • 这个快速示例展示了如何重载碱基调用,并根据需要进行重构以进行优化。任何通用代码都应该放在受保护的方法中。我已编辑以显示此内容。
    • 我想更多地朝着@Sergey 方法的方向发展,以利用 ModelBinder 等。您的解决方案不允许我使用它们打算使用的 WebApi 功能(可插入序列化程序、模型验证等)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-05
    • 2012-08-22
    • 1970-01-01
    相关资源
    最近更新 更多