2015-01-15 2 views
3

В настоящее время я пытаюсь получить наследование в WebApi, как хотелось бы. Возможно, вы можете указать мне в правильном направлении?Asp.Net WebApi Inheritance с BaseController

Моя цель - создать общий проект WebApi, который может быть повторно использован в нескольких других проектах WebApi.

Например: у меня есть многопользовательский UserController, который может обрабатывать логин для нескольких веб-сайтов. Теперь я создаю новый WebSite и просто добавляю UserController к вновь созданному проекту, который просто работает.

Но теперь требуется изменение нового WebSite, и мне нужно перегрузить методы UserController, чтобы отразить эти изменения, не изменяя общий контроллер.

То, что я хочу, чтобы достичь можно увидеть в следующем фрагменте кода (конечно, это не будет компилироваться, так как C# жалуется не подходящий метод перегружать Found.)

// 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» на «динамический», но это просто неправильно, и ModelBinder, конечно, не будет работать так, как предполагалось.

Любые идеи, как вы могли бы решить это?

Заранее спасибо

ответ

7

Вы можете сделать свой 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); 
    } 
} 
+0

Спасибо за ваши предложения, это, кажется, хороший способ. Но мой BaseApiController имел бы> 10-15 действий WebApi. Поэтому мне нужно будет сделать это BaseApiController . Есть ли другой способ узнать? – coalmee

0

Если вытащить переменную и читать его внутри метода легче перегрузить

/// <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

+0

Спасибо за предложение. Это, по-видимому, не дает преимущества использования «динамического» (с JObject, например, для сериализации). Кроме того, ваше решение добавляет много дублированного кода, похоже, больше нет смысла использовать общий контроллер. – coalmee

+0

Этот быстрый пример показывает, как перегрузить базовый вызов, рефакторинг по мере необходимости для оптимизации. Любой общий код должен быть помещен в защищенный метод. Я отредактировал это, чтобы показать это. –

+0

Я хочу пойти больше в направлении подхода @Sergey, использовать ModelBinder и т. Д. Ваше решение не позволяет мне использовать функции WebApi, как они были предназначены для использования (подключаемые сериализаторы, проверка модели и т. Д.). – coalmee

Смежные вопросы