进入控制器后进行后期绑定动态解析模型 [英] Late binding Dynamically Resolve Models after entering controller

查看:86
本文介绍了进入控制器后进行后期绑定动态解析模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种在控制器中执行动作后解析模型的方法,最简单的描述问题的方法是:

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆