是否可以将委托传递给控制器​​操作?

时间:2013-03-28 05:35:11

标签: c# asp.net-mvc linq delegates controller

我想将自定义过滤器传递给控制器​​中的操作方法。 我试着像那样定义它。

public ActionResult GetResult(Func<Fault,bool> filter)
{
    List<Fault> faultList;
    using (var _context = new myDB())
    {
        faultList = 
            from f in _context.Faults
            where filter(f)
            select f;
    }
    return Json(faultList);
}

但是当我运行动作时出现错误

  

没有为此对象定义无参数构造函数。

     

在System.RuntimeType.CreateInstanceSlow的System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,Boolean publicOnly,Boolean noCheck,Boolean&amp; canBeCached,RuntimeMethodHandleInternal&amp; ctor,Boolean&amp; bNeedSecurityCheck)中(布尔值publicOnly,布尔值skipCheckThis,布尔fillCache,StackCrawlMark&amp; stackMark )System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache,StackCrawlMark&amp; stackMark)System.Activator.CreateInstance(Type type,Boolean nonPublic)at System.Activator.CreateInstance(Type type)at System.Web.Mvc系统中System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)的System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext,ModelBindingContext bindingContext)中的.DefaultModelBinder.CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType) .Web.Mvc.Contr System.Web.Mvc上System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext,String actionName)的System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext,ActionDescriptor actionDescriptor)中的ollerActionInvoker.GetParameterValue(ControllerContext controllerContext,ParameterDescriptor parameterDescriptor) System.Web.Mvc.MvcHandler上System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)的System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)中的.Controller.ExecuteCore() 。&lt;&gt; c_ DisplayClass6。&lt;&gt; c _DisplayClassb.b_ 5()在System.Web.Mvc.Async.AsyncResultWrapper。&lt;&gt; c _DisplayClass1 .b_ 0()在System.Web.Mvc.Async.AsyncResultWrapper。&lt;&gt; c _DisplayClass8 1.b__7(IAsyncResult _) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult 1.End()在System.Web.Mvc.MvcHandler。&lt; System.Web.Mvc.SecurityUtil.ProcessInA上的System.Web.Mvc.SecurityUtil.b__0(操作f)中的&gt; c_ DisplayClasse.b _d() System.Web.HttpApplication.CallHandlerExecutionStep.System上的System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult结果)中的System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)中的pplicationTrust(Action action)。 System.Web.HttpApplication.ExecuteStep中的Web.HttpApplication.IExecutionStep.Execute()(IExecutionStep step,Boolean&amp; completedSynchronously)

事件是否可以做这样的事情?

如果没有通过委托,你能建议另一种方式吗?

4 个答案:

答案 0 :(得分:2)

当我理解你的问题时,我会说这是不可能的。

ASP中的ASP.NET MVC操作方法是一种阻止映射http请求(url路由)的入口点,其中在接收到http请求后触发了Action方法。因此,该方法的输入参数实际上是将http或请求参数从http请求反序列化(或映射)到强类型对象的结果。当MVC框架创建对象时,它会查找无参数构造函数。它涉及参考类型的数据容器。

另一件事是通过http请求发送功能(逻辑)并将其映射到NET委托。由于NET是编译框架 - 而不是解释器 - 没有办法将.NET代码作为文本(例如C#代码)发送并将其映射到委托(例如,我们可以从Action方法返回javascript代码)。

如果即使可以在运行时编译.NET代码(有一些方法),最后还是可能会向Action方法注入.NET代码,这会导致安全问题。

答案 1 :(得分:0)

我不知道是否可以将一个委托传递给一个Action,但我有一个替代方案的建议。您可以将参数传递给操作,并根据该值将适当的函数分配给filter委托。

这是一个示例控制台应用程序来说明我的想法:

public enum Cases { Case1, Case2, Case3 };

class Program
{
    private static bool Test1(int test) { return test == 1; }

    private static bool Test2(int test) { return test == 2; }

    private static bool Test3(int test) { return test == 3; }

    public static void Main()
    {
        RunTest(Cases.Case1);
        RunTest(Cases.Case2);
        RunTest(Cases.Case3);

        Console.ReadLine();
    }


    private static void RunTest(Cases testCase)
    {
        var list = new List<int> {1, 2, 3};
        Func<int, bool> del;

        switch (testCase)
        {
            case Cases.Case1:
                del = Test1;
                break;
            case Cases.Case2:
                del = Test2;
                break;
            case Cases.Case3:
                del = Test3;
                break;
            default:
                throw new InvalidDataException();
        }

        list.ForEach( i => Console.WriteLine(del(i) ? i.ToString() : "--")  );
    }
}

答案 2 :(得分:0)

绝对可以通过代表。 假设你有一个如下命令类

public class MyCommand<T>{

Action myAction;
Func<T, bool> canExecute;

public MyCommand(Action<T> actionToBeExecuted, Func<T, bool> canExecute)
{
this.myAction = actionToBeExecuted;
this.canExecute = canExecute;
}

public void ExecuteMyCommand<T>(T param)
{
if(this.canExecute(param))
   this.myAction(param);
}
}

我相信上面的代码为您提供了一个示例,您可以继续前进。

答案 3 :(得分:0)

虽然您尝试做的事情并非严格可行,但仍有办法做类似的事情。

我没有在HTTP请求中传递来自用户的Func,而是在我的代码中使用Func作为接缝进行测试和其他目的。我遇到了同样的问题,但通过重载具有不同参数的方法解决了这个问题。

这就是我所拥有的:

public class SomeController : Controller
{
    [HttpGet]
    public ActionResult SomeAction(string q, Func<string, SomeResultType> fn = null) 
    {
        fn = fn ?? SomeDefaultFn;
        ...

        return View(...);
    }
}

由于@Bronek在答案中说明的原因,这不起作用。但是,由于我想提供默认值,只需要重载我的方法签名就可以了。

public class SomeController : Controller
{
   [HttpGet]
   public Action SomeAction(string q)
   {
       // mvc will execute this action and pass
       // my default off to the next method
       return SomeAction(q, SomeDefaultFn);
   }

   public ActionResult SomeAction(string q, Func<string, SomeResultType> fn)
   {
        ...
        return View(...);
   }
}

在另一个地方,我有以下内容:

public class SomeController : Controller
{ 
    [HttpGet]
    public ActionResult SomeAction(string q, string filterType)
    {
        return SomeAction(q, FilterFactory.Build(filterType));
    }

    ...
}