[英]Creating per-request controller/action based formatters in ASP.NET 5
I'm trying to implement HATEOAS in my ASP rest API, changing the ReferenceResolverProvider
. 我正在尝试在我的ASP rest API中实现HATEOAS,更改
ReferenceResolverProvider
。
The problem is, that depending on which controller I use, I'd like to use different ReferenceResolvers
, because I need to behave differently for each Controller. 问题是,根据我使用的控制器,我想使用不同的
ReferenceResolvers
,因为我需要为每个Controller表现不同。
Now I have universal options: 现在我有通用的选择:
services.AddMvc()
.AddJsonOptions(option => option.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver())
.AddJsonOptions(options => options.SerializerSettings.ReferenceResolverProvider = () => new RoomsReferenceResolver<Room>())
.AddJsonOptions(options => options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects);
And I want to have something like this: 我想要这样的东西:
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);
You seem to be wanting to create a per-controller specific formatters. 您似乎想要创建一个每个控制器特定的格式化程序。 This can be achieved by using a filter called
IResourceFilter
. 这可以通过使用名为
IResourceFilter
的过滤器来实现。 A quick example: 一个简单的例子:
[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" };
}
If you are curious about the filter execution order, following is an example of the sequence of them: 如果您对过滤器执行顺序感到好奇,以下是它们序列的示例:
Inside TestAuthorizationFilter.OnAuthorization
Inside TestResourceFilter.OnResourceExecuting
Inside TestActionFilter.OnActionExecuting
Inside Home.Index
Inside TestActionFilter.OnActionExecuted
Inside TestResultFilter.OnResultExecuting
Inside TestResultFilter.OnResultExecuted
Inside TestResourceFilter.OnResourceExecuted
Interesting problem. 有趣的问题。
What about making the ReferenceResolver a facade: 如何使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();
}
Then you should be able to do: 然后你应该能够做到:
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ReferenceResolverProvider = () => {
return new ControllerReferenceResolverFacade(
services.BuildServiceProvider().GetService<IHttpContextAccessor>());
});
This might not be exactly what you need but it might help you get started? 这可能不是您需要的,但它可能会帮助您入门?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.