【问题标题】:Bind Controller Context with Ninject使用 Ninject 绑定控制器上下文
【发布时间】:2013-05-23 07:44:51
【问题描述】:

我有一个创建 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 的引用。

我查看了提供者、工厂、解析器等。 但找不到合适的解决方案。

感谢任何帮助! 干杯

【问题讨论】:

  • 您是从控制器调用 PdfCreatorService 吗?如果是这样,为什么不将控制器上下文作为参数传递。或者从设计的角度来看甚至更好,提取您需要的信息并将其作为简单参数传递给您的 PdfCreatorService。
  • @Kenneth 不,如堆栈中所示,我没有直接从控制器调用 PdfCreatorService。你能解释一下,我如何使用一个简单的参数来传递 ControllerContext ?
  • 那么您是从 Web 服务访问它吗?如果是这样,由于您没有调用控制器,因此也不会有可用的控制器上下文。
  • 我正在调用控制器 -> 中间层 -> pdfService 但是中间层不能有对 ControllerContext 的引用。

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


【解决方案1】:

好的。我想出了一个我很满意的解决方案。
这是我检索 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();
    }
}

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

【讨论】:

    【解决方案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);
    

    【讨论】:

    • 感谢您的回答。不过,这感觉有点像作弊。由于您只是将其保存到 HttpContext.Current.Request 中。因此有点绕过ninject。 Ninject 几乎是多余的,因为 PdfService 可以从 HttpContext.Current.Request 加载它而无需 ninject...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    相关资源
    最近更新 更多