2013-03-28 110 views
1

我想将自定义过滤器传递给我的控制器中的操作方法。 我尝试像那样定义它。是否可以将委托传递给控制器​​操作?

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.RuntimeTypeHandle.CreateInstance(RuntimeType类型,布尔publicOnly,布尔NOCHECK,布尔& canBeCached,RuntimeMethodHandleInternal &构造函数,布尔& bNeedSecurityCheck)在System.RuntimeType.CreateInstanceSlow(布尔publicOnly,布尔skipCheckThis,布尔fillCache,StackCrawlMark &在System.Web的System.Activator.CreateInstance(Type类型)System.Activator.CreateInstance(类型类型,布尔型非公共)上的System.RuntimeType.CreateInstanceDefaultCtor(布尔publicOnly,布尔skipCheckThis,布尔fillCache,StackCrawlMark & stackMark) System.Web.Mvc上的Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)。 DefaultModelBinder.BindComplexModel(ControllerContext controllerContext,ModelBindingContext的BindingContext)在System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext,ModelBindingContext的BindingContext)在System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext,ParameterDescriptor parameterDescriptor)在System.Web.Mvc .ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext,ActionDescriptor actionDescriptor)at System.Web.Mvc.ControllerBase.Execute System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext,String actionName)System.Web.Mvc.Controller.ExecuteCore() (RequestContext requestContext)位于System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)位于System.Web.Mvc.MvcHandler。 <> c_ DisplayClass6。 <> c _DisplayClassb.b_ 5()at System.Web.Mvc.Async.AsyncResultWrapper。 <> c _DisplayClass1.b_ 0()at System.Web.Mvc.Async.AsyncResultWrapper。 <> c _DisplayClass8 1.b__7(IAsyncResult _) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult 1.End()at System.Web.Mvc.MvcHandler。 <> C_ DisplayClasse.b _d()在System.Web.Mvc.SecurityUtil.b__0(动作f)位于System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(动作动作)在System.Web.Mvc.MvcHandler.EndProcessRequest( IAsyncResult asyncResult)System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult结果)在System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()在System.Web.HttpApplication。 ExecuteStep(IExecutionStep步骤,布尔型&同步完成)

是否可以执行类似事件?

如果不是通过委托可以建议另一种方式吗?

+1

你发送给这个动作是什么数据?您如何期望从该数据创建的'Func 过滤器? – nemesv 2013-03-28 06:10:35

+0

我在想像@ Html.Action(“GetResults”,新的{filter =(f => f.TypeID == 1)})或类似的东西... – Mortalus 2013-03-28 07:25:14

回答

2

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

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

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

最后一件事,即使可以在运行时编译.NET代码(有一些方法),将.NET代码注入Action方法的可能性也会导致安全问题。

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() : "--") ); 
    } 
} 
+0

这不会削减它,因为我必须通过我的控制器的过滤策略,此外您的答案不能解释错误信息。 – Mortalus 2013-03-28 18:01:28

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

我相信上面的代码给你一个例子,你可以在沿着进行。

+0

对不起,但这无助于我在MVC中的斗争,我知道它可以传递一个委托我只是不明白为什么MVC给我一个错误。 – Mortalus 2013-03-28 18:00:32

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

    ... 
}