2015-10-31 5 views
3

Я пытаюсь реализовать HATEOAS в моем ASP rest API, изменяя ReferenceResolverProvider.Создание обработчиков для каждого запроса/основанных на действиях форматировщиков в ASP.NET 5

Проблема в том, что в зависимости от того, какой контроллер я использую, я хотел бы использовать разные ReferenceResolvers, потому что мне нужно вести себя по-разному для каждого контроллера.

Теперь у меня есть универсальные варианты:

services.AddMvc() 
      .AddJsonOptions(option => option.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()) 
      .AddJsonOptions(options => options.SerializerSettings.ReferenceResolverProvider =() => new RoomsReferenceResolver<Room>()) 
      .AddJsonOptions(options => options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects); 

И я хочу, чтобы иметь что-то вроде этого:

services.AddMvc() 
      .AddJsonOptions(option => option.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()) 
      .AddJsonOptions<RoomsController>(options => options.SerializerSettings.ReferenceResolverProvider =() => new RoomsReferenceResolver<Room>()) 
      .AddJsonOptions(options => options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects); 

ответ

2

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

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 
public class CamelCaseJsonFormatterResourceFilter : Attribute, IResourceFilter 
{ 
    private readonly JsonSerializerSettings serializerSettings; 

    public CamelCaseJsonFormatterResourceFilter() 
    { 
     // Since the contract resolver creates the json contract for the types it needs to deserialize/serialize, 
     // cache it as its expensive 
     serializerSettings = new JsonSerializerSettings() 
     { 
      ContractResolver = new CamelCasePropertyNamesContractResolver() 
     }; 
    } 

    public void OnResourceExecuted(ResourceExecutedContext context) 
    { 

    } 

    public void OnResourceExecuting(ResourceExecutingContext context) 
    { 
     // remove existing input formatter and add a new one 
     var camelcaseInputFormatter = new JsonInputFormatter(serializerSettings); 
     var inputFormatter = context.InputFormatters.FirstOrDefault(frmtr => frmtr is JsonInputFormatter); 
     if (inputFormatter != null) 
     { 
      context.InputFormatters.Remove(inputFormatter); 
     } 
     context.InputFormatters.Add(camelcaseInputFormatter); 

     // remove existing output formatter and add a new one 
     var camelcaseOutputFormatter = new JsonOutputFormatter(serializerSettings); 
     var outputFormatter = context.OutputFormatters.FirstOrDefault(frmtr => frmtr is JsonOutputFormatter); 
     if (outputFormatter != null) 
     { 
      context.OutputFormatters.Remove(outputFormatter); 
     } 
     context.OutputFormatters.Add(camelcaseOutputFormatter); 
    } 
} 

// Here I am using the filter to indicate that only the Index action should give back a camelCamse response 
public class HomeController : Controller 
{ 
    [CamelCaseJsonFormatterResourceFilter] 
    public Person Index() 
    { 
     return new Person() { Id = 10, AddressInfo = "asdfsadfads" }; 
    } 

    public Person Blah() 
    { 
     return new Person() { Id = 10, AddressInfo = "asdfsadfads" }; 
    } 

Если вы любопытны о порядке исполнения фильтра Ниже приведен пример последовательности из них:

Inside TestAuthorizationFilter.OnAuthorization 
Inside TestResourceFilter.OnResourceExecuting 
Inside TestActionFilter.OnActionExecuting 
Inside Home.Index 
Inside TestActionFilter.OnActionExecuted 
Inside TestResultFilter.OnResultExecuting 
Inside TestResultFilter.OnResultExecuted 
Inside TestResourceFilter.OnResourceExecuted 
+1

Кажется нет «InputFormatters» в «ResourceExecutingContext» на. чистый ядро. Тогда как мы можем получить формулу? – HappyLiang

0

Интересная проблема.

Что застилать ReferenceResolver фасад:

class ControllerReferenceResolverFacade : IReferenceResolver 
    { 
     private IHttpContextAccessor _context; 

     public ControllerReferenceResolverFacade(IHttpContextAccessor context) 
     { 
      _context = context; 
     } 

     public void AddReference(object context, string reference, object value) 
     { 
      if ((string)_context.HttpContext.RequestServices.GetService<ActionContext>().RouteData.Values["Controller"] == "HomeController") 
      { 
       // pass off to HomeReferenceResolver 
      } 
      throw new NotImplementedException(); 
     } 

Тогда вы должны быть в состоянии сделать:

services.AddMvc() 
    .AddJsonOptions(options => options.SerializerSettings.ReferenceResolverProvider =() => { 
     return new ControllerReferenceResolverFacade(
      services.BuildServiceProvider().GetService<IHttpContextAccessor>()); 
     }); 

Это не может быть именно то, что вам нужно, но это может помочь вам начать работу?