进入控制器后进行后期绑定动态解析模型

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

public DTO[] Get(string filterName)
{
    //How can I do this
    this.Resolve<MyCustomType>("MyParamName");
}

如果您要查找有关我为什么要这样做的更多信息,可以继续阅读以获取完整图片

TL; DR

我正在寻找一种解决模型请求的方法,给定一个始终从查询字符串中解析的参数名称,该如何从启动动态注册过滤器。我有一个要处理注册过滤器的类。

在我的启动类中,我希望能够向我的restServices动态注册过滤器。我有一个用来传递给我的自定义ControllerFeatureProvider的选项,大致如下所示:

public class DynamicControllerOptions<TEntity,TDTO>
{
    Dictionary<string,Func<HttpContext,Expression<Func<TEntity,bool>>>> _funcNameToEndpointResolverMap
        = new Dictionary<string,bool>>>>();
    Dictionary<string,List<ParameterOptions>> _filterParamsMap = new Dictionary<string,List<ParameterOptions>>();

    public void AddFilter(string filterName,bool>> filter)
    {
        this._funcNameToEndpointResolverMap.Add(filterName,(httpContext) =>  filter);
    }
    public void AddFilter<T1>(string filterName,Func<T1,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提供过滤器。

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的情况下,我很难弄清楚如何动态解析模型,我想做这样的事情来获取模型,但这是不起作用的伪代码

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);
}

深入研究源代码之后,我看到了一些有前途的东西ModelBinderFactoryControllerActionInvoker这些类用于模型绑定的管道中,

我希望公开一个简单的接口来解析QueryString中的参数名称,如下所示:

ModelBindingContext context = new ModelBindingContext();
return context.GetvalueFor<T>("MyParamName");

但是,我看到的从模型绑定器解析模型的唯一方法是创建伪造的控制器描述符并模拟大量内容。

如何将后期绑定参数接受到我的控制器中?

epkaixuan 回答:进入控制器后进行后期绑定动态解析模型

我同意你的想法

  

服务需要从get列表中过滤数据,但是我不想编写提供过滤器所需的全部服务

为什么要为每种可能的组合编写小部件/过滤器/端点?

仅提供基本操作即可获取所有数据/属性。然后使用GraphQL允许最终用户过滤(模型)以满足他们的需求。

来自GraphQL

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API,gives clients the power to ask for exactly what they need and nothing more,makes it easier to evolve APIs over time,and enables powerful developer tools

,

我们已经做到了,我们的代码引用了这个站点: https://prideparrot.com/blog/archive/2012/6/gotchas_in_explicit_model_binding

具体来说,看一下我们的代码,诀窍是在您的控制器方法中接受FormCollection,然后使用模型绑定器,模型和表单数据:

示例摘自链接:

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)

,

我最终写了动态控制器。解决该问题的方法。

private static TypeBuilder GetTypeBuilder(string assemblyName)
{
    var assemName = new AssemblyName(assemblyName);
    var assemBuilder = AssemblyBuilder.DefineDynamicAssembly(assemName,AssemblyBuilderAccess.Run);
    // Create a dynamic module in Dynamic Assembly.
    var moduleBuilder = assemBuilder.DefineDynamicModule("DynamicModule");
    var tb = moduleBuilder.DefineType(assemblyName,TypeAttributes.Public |
            TypeAttributes.Class |
            TypeAttributes.AutoClass |
            TypeAttributes.AnsiClass |
            TypeAttributes.BeforeFieldInit |
            TypeAttributes.AutoLayout,null);

    return tb;
}

我目前正在对该方法中的func进行硬编码,但是我敢肯定,如果需要的话,您可以弄清楚如何将其传递出去。

public static Type CompileResultType(string typeSignature)
{
    TypeBuilder tb = GetTypeBuilder(typeSignature);

    tb.SetParent(typeof(DynamicControllerBase));

    ConstructorBuilder ctor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

    // For this controller,I only want a Get method to server Get request
    MethodBuilder myGetMethod =
        tb.DefineMethod("Get",MethodAttributes.Public,typeof(String),new Type[] { typeof(Test),typeof(String) });

    // Define parameters
    var parameterBuilder = myGetMethod.DefineParameter(
        position: 1,// 0 is the return value,1 is the 1st param,2 is 2nd,etc.
        attributes: ParameterAttributes.None,strParamName: "test"
    );
    var attributeBuilder
        = new CustomAttributeBuilder(typeof(FromServicesAttribute).GetConstructor(Type.EmptyTypes),Type.EmptyTypes);
    parameterBuilder.SetCustomAttribute(attributeBuilder);

    // Define parameters
    myGetMethod.DefineParameter(
        position: 2,strParamName: "stringParam"
    );

    // Generate IL for method.
    ILGenerator myMethodIL = myGetMethod.GetILGenerator();
    Func<string,string> method = (v) => "Poop";

    Func<Test,string,string> method1 = (v,s) => v.Name + s;

    myMethodIL.Emit(OpCodes.Jmp,method1.Method);
    myMethodIL.Emit(OpCodes.Ret);

    return tb.CreateType();
}
本文链接:https://www.f2er.com/3113611.html

大家都在问