【问题标题】:How to fake an HttpContext and its HttpRequest to inject them in a service constructor如何伪造 HttpContext 及其 HttpRequest 以将它们注入服务构造函数
【发布时间】:2012-11-19 19:01:12
【问题描述】:

在控制台应用程序中,我想使用通常需要将当前 http 上下文传递给其构造函数的服务。我正在使用 Ninject,我想我可以简单地伪造一个 http 上下文并定义正确的绑定,但是我已经为此苦苦挣扎了几个小时而没有成功。

详情:

该服务实际上是一个来自 ASP.Net MVC 项目的邮件服务。我也在为 IoC 使用 Ninject。邮件服务需要将当前的 http 上下文传递给它的构造函数。我按如下方式进行绑定:

kernel.Bind<IMyEmailService>().To<MyEmailService>()
    .WithConstructorArgument("httpContext", ninjectContext => new HttpContextWrapper(HttpContext.Current));

但是,我现在想在控制台应用程序中使用此邮件服务,该应用程序将用于在夜间运行自动化任务。为了做到这一点,我想我可以简单地伪造一个 http 上下文,但我已经为此苦苦挣扎了几个小时。

上下文中的所有邮件服务需求都是这两个属性:

  • httpContext.Request.UserHostAddress
  • httpContext.Request.RawUrl

我以为我可以做这样的事情,但是:

定义我自己的假请求类:

public class AutomatedTaskHttpRequest : SimpleWorkerRequest
{
    public string UserHostAddress;
    public string RawUrl;

    public AutomatedTaskHttpRequest(string appVirtualDir, string appPhysicalDir, string page, string query, TextWriter output)
        : base(appVirtualDir, appPhysicalDir, page, query, output)
    {
        this.UserHostAddress = "127.0.0.1";
        this.RawUrl = null;
    }
}

定义我自己的上下文类:

public class AutomatedTasksHttpContext
{
    public AutomatedTaskHttpRequest Request;

    public AutomatedTasksHttpContext()
    {
        this.Request = new AutomatedTaskHttpRequest("", "", "", null, new StringWriter());
    }
}

并在我的控制台应用程序中将其绑定如下:

   kernel.Bind<IUpDirEmailService>().To<UpDirEmailService>()
        .WithConstructorArgument("httpContext", ninjectContext => new AutomatedTasksHttpContext());

不幸的是,这行不通。我尝试了各种变体,但没有一个有效。请多多包涵。所有 IoC 的东西对我来说都很新鲜。

【问题讨论】:

    标签: asp.net-mvc-3 inversion-of-control ninject console-application ninject-2


    【解决方案1】:

    我最近回答了关于使用 HttpContextFactory 进行测试的问题,它对控制台应用程序采用了不同的方法。

    public static class HttpContextFactory
        {
            [ThreadStatic]
            private static HttpContextBase _serviceHttpContext;
    
            public static void SetHttpContext(HttpContextBase httpContextBase)
            {
                _serviceHttpContext = httpContextBase;
            }
    
            public static HttpContextBase GetHttpContext()
            {
                if (_serviceHttpContext!= null)
                {
                    return _serviceHttpContext;
                }
    
                if (HttpContext.Current != null)
                {
                    return new HttpContextWrapper(HttpContext.Current);
                }
                return null;
            }
        }
    

    然后在你的代码中:

    var rawUrl = HttpContextFactory.GetHttpContext().Request.RawUrl;
    

    然后在您的测试中使用该属性作为接缝

    HttpContextFactory.SetHttpContext(HttpMocks.HttpContext());
    

    其中 HttpMocks 具有以下内容,并将针对您的测试进行调整:

    public static HttpContextBase HttpContext()
          {
              var context = MockRepository.GenerateMock<HttpContextBase>();
              context.Stub(r => r.Request).Return(HttpRequest());
              // and stub out whatever else you need to, like session etc
              return context;
          }
    
    
          public static HttpRequestBase HttpRequest()
          {
              var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
              httpRequest.Stub(r => r.UserHostAddress).Return("127.0.0.1"); 
              httpRequest.Stub(r => r.RawUrl).Return(null); 
              return httpRequest;
          }
    

    【讨论】:

    • 我认为模拟是用于测试的。在这里,我正在开发的不是一个测试工具,而是一个真正的控制台应用程序。另外,我不确定如何将工厂与 Ninject 一起使用。它是我将传递给我的服务构造函数的上下文工厂而不是实际的上下文吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 2018-11-23
    • 2023-03-28
    • 1970-01-01
    • 2019-04-25
    相关资源
    最近更新 更多