进入控制器后后期绑定动态解析模型 [英] Late binding Dynamically Resolve Models after entering controller
问题描述
我正在寻找一种在控制器中进入操作后解决模型的方法,描述问题的最简单方法是:
I'm looking for a way to resolve a model after entering into an action in a controller , the simplest way to describe the problem would be:
public DTO[] Get(string filterName)
{
//How can I do this
this.Resolve<MyCustomType>("MyParamName");
}
如果您正在寻找有关我为什么要这样做的更多信息,您可以继续阅读以了解全貌
If you're looking for more information on why I'm trying to do that you can continue reading to get the full picture
TL;DR
我正在寻找一种方法来解析模型和请求,给定一个始终从查询字符串解析的参数名称如何从启动动态注册过滤器.我有一个类将处理注册我的过滤器.
I'm looking for a way to resolve a model a request, given a parameter name that will always be resolved from query string How can I dynamically register filters from the startup. I have a class which is going to handle registering my filters.
在我的启动类中,我希望能够使用我的 restServices 动态注册过滤器.我有一个选项可用于传递给我的自定义 ControllerFeatureProvider,大致如下所示:
In my startup class I want to be able to dynamically register filters with my restServices. I have an options that I'm using to pass to my custom ControllerFeatureProvider which roughly looks like so:
public class DynamicControllerOptions<TEntity, TDTO>
{
Dictionary<string, Func<HttpContext, Expression<Func<TEntity, bool>>>> _funcNameToEndpointResolverMap
= new Dictionary<string, Func<HttpContext, Expression<Func<TEntity, bool>>>>();
Dictionary<string, List<ParameterOptions>> _filterParamsMap = new Dictionary<string, List<ParameterOptions>>();
public void AddFilter(string filterName, Expression<Func<TEntity, bool>> filter)
{
this._funcNameToEndpointResolverMap.Add(filterName, (httpContext) => filter);
}
public void AddFilter<T1>(string filterName, Func<T1, Expression<Func<TEntity, bool>>> filterResolver,
string param1Name = "param1")
{
var parameters = new List<ParameterOptions> { new ParameterOptions { Name = param1Name, Type = typeof(T1) } };
this._filterParamsMap.Add(filterName, parameters);
this._funcNameToEndpointResolverMap.Add(filterName, (httpContext) => {
T1 parameter = this.ResolveParameterFromContext<T1>(httpContext, param1Name);
var filter = filterResolver(parameter);
return filter;
});
}
}
我的控制器将跟踪选项并使用它们为分页端点和 OData 提供过滤器.
My Controller will keep track of the options and use them to provide filters for paging endpoints and OData.
public class DynamicControllerBase<TEntity, TDTO> : ControllerBase
{
protected DynamicControllerOptions<TEntity, TDTO> _options;
//...
public TDTO[] GetList(string filterName = "")
{
Expression<Func<TEntity, bool>> filter =
this.Options.ResolveFilter(filterName, this.HttpContext);
var entities = this._context.DbSet<TEntity>().Where(filter).ToList();
return entities.ToDTO<TDTO>();
}
}
我无法弄清楚如何在给定 HttpContext 的情况下动态解析模型,我想做这样的事情来获取模型,但这是行不通的伪代码
I'm having trouble figuring out how to dynamically resolve a model given the HttpContext, I would think to do something like this to obtain the model but this is pseudo-code that doesn't work
private Task<T> ResolveParameterFromContext<T>(HttpContext httpContext, string parameterName)
{
//var modelBindingContext = httpContext.ToModelBindingContext();
//var modelBinder = httpContext.Features.OfType<IModelBinder>().Single();
//return modelBinder.BindModelAsync<T>(parameterName);
}
深入挖掘源代码后,我看到了一些有希望的东西 ModelBinderFactory 和 ControllerActionInvoker 这些类在管道中用于模型绑定,
After Digging into the Source, I saw some promising things ModelBinderFactory and the ControllerActionInvoker These classes are used in the pipeline for model binding,
我希望公开一个简单的接口来解析 QueryString 中的参数名称,如下所示:
I would expect the to expose a simple interface to resolve a parameter name from the QueryString, something like this:
ModelBindingContext context = new ModelBindingContext();
return context.GetValueFor<T>("MyParamName");
然而,我认为从模型绑定器解析模型的唯一方法是创建假控制器描述符并模拟大量事物.
However, the only way I see to resolve a model from the model binder is to create fake controller descriptors and mock a ton of things.
如何在控制器中接受后期绑定参数?
How can I accept late bound parameters into my contoller?
推荐答案
我们已经做到了,我们的代码引用了这个站点:https://prideparrot.com/blog/archive/2012/6/gotchas_in_explicit_model_binding
We've done this, our code references this site: https://prideparrot.com/blog/archive/2012/6/gotchas_in_explicit_model_binding
具体来说,看看我们的代码,在你的控制器方法中接受一个 FormCollection 然后使用模型绑定器、模型和表单数据有什么技巧:
Specifically, looking at our code, what does the trick is accepting a FormCollection in your controller method and then using the model binder, model, and form data:
来自链接的示例:
public ActionResult Save(FormCollection form)
{
var empType = Type.GetType("Example.Models.Employee");
var emp = Activator.CreateInstance(empType);
var binder = Binders.GetBinder(empType);
var bindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => emp, empType),
ModelState = ModelState,
ValueProvider = form
};
binder.BindModel(ControllerContext, bindingContext);
if (ModelState.IsValid)
{
_empRepo.Save(emp);
return RedirectToAction("Index");
}
return View();
}
(注意:该站点似乎已关闭,链接指向 archive.org)
(Note: the site appears to be down, link is to to archive.org)
这篇关于进入控制器后后期绑定动态解析模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!