使用Ninject绑定控制器上下文

时间:2013-05-28 10:58:23

标签: c# asp.net-mvc asp.net-mvc-4 ninject ninject-2

我有一个创建pdf所需的服务类,需要注入ControllerContext才能呈现html => pdf。 此服务通过中间层调用,该中间层没有引用web / mvc项目。这很好,因为ninject会完成所有必需的服务注入等。 这就是服务的样子(为了这些目的而简化)

public class PdfCreatorService : AbstractUrlBasedPdfCreatorService
{
    [Inject]
    public ControllerContext ControllerContext { get; set; }

    public override byte[] CreateReport(int reportId)
    {
        var result = new PdfController().CreateReport(reportId);
        using (var it = new ResponseCapture(ControllerContext.RequestContext))
        {
            result.ExecuteResult(ControllerContext);
            return it.ReadAllContents();
        }
    }
}

这是简化的调用堆栈:

  

Web.HomeController.SendEmailWithPdf(int id)调用:
  MiddleTier.BusinessLogic.SendEmailWithPdf(int id)调用:
  Web.Services.PdfCreatorService.CreateReport(int id)

Ninject正在达到PdfCreatorService,没问题,但是:我需要以某种方式将ControllerContext从HomeController(通过中间层)转发到PdfCreatorService 。 虽然中间层不能引用ControllerContext。

我看过提供商,工厂,解析器等。 但找不到合适的解决方案。

任何帮助表示赞赏! 干杯

2 个答案:

答案 0 :(得分:4)

行。我想出了一个我很满意的解决方案 以下是我正在检索ControllerContext的方法:

public class PdfCreatorService 
{
    [Inject]
    public ControllerContextProvider contextProvider { get; set; }
    [Inject]
    public PdfController pdfController { get; set; }

    public override byte[] CreateReport(int reportId)
    {
        var context = contextProvider.GetControllerContext();
        using (var stream = new ResponseCapture(context.RequestContext))
        {
            // Setup Controller
            var routeData = new RouteData(context.RouteData.Route, context.RouteData.RouteHandler);
            routeData.Values.Add("action", "CreateReport");
            routeData.Values.Add("controller", "Pdf");
            routeData.Values.Add("id", reportId);
            var pdfContext = new ControllerContext(context.HttpContext, routeData, pdfController);

            // Execute Controller
            var result = pdfController.CreateReport(reportId);
            result.ExecuteResult(pdfContext);

            return stream.ReadAllContents();
        }
    }
}

这是在原始控制器中设置上下文的方法:

public abstract class HomeController : Controller
{
    [Inject]
    public ControllerContextProvider ControllerContextProvider { get; set; }

    protected override IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
    {
        ControllerContextProvider.GetControllerContext = () => ControllerContext;
        return base.BeginExecute(requestContext, callback, state);
    }
}

这就是提供者类的样子:

public class ControllerContextProvider
{
    public Func<ControllerContext> GetControllerContext { get; set; }
}

这就是我绑定它的方式:

public class PortalNinjectModule : NinjectModule
{
    public override void Load()
    {
        Bind<ControllerContextProvider>().ToSelf().InRequestScope();
    }
}

仍然有兴趣看看是否有人有更优雅的解决方案。

答案 1 :(得分:2)

您可以创建自定义控制器工厂。

public class MyControllerFactory : DefaultControllerFactory
{
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controller = base.CreateController(requestContext, controllerName);
        HttpContext.Current.Request["controllerInstance"] = controller;
        return controller;
    }
}

您需要在global.asax中注册此控制器:

ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));

之后,您可以配置Ninject以从请求中解析ControllerContext:

kernel.Bind<ControllerContext>().ToMethod(ctx => ((Controller)HttpContext.Current.Request["controllerInstance"]).ControllerContext);