System.ArgumentNullException: 值不能为 null - Umbraco HTTPContext 保存和发布

System.ArgumentNullException: Value cannot be null - Umbraco HTTPContext on save and publish

来源:https://gist.github.com/sniffdk/7600822

以下代码是 运行 由 activity 在 http 请求之外编写的,因此我需要模拟 http 上下文。

我已经像这样模拟了 http 上下文:

public class GetUmbracoServiceMockedHttpContext : IGetUmbracoService
{
    private UmbracoHelper umbracoHelper;

    public T GetService<T>()
        where T : IService
    {
        UmbracoContext context = UmbracoContext.Current;

        if (context == null)
        {
            var dummyHttpContext = new HttpContextWrapper(new HttpContext(new SimpleWorkerRequest("blah.aspx", "", new StringWriter())));
            context = UmbracoContext.EnsureContext(
                dummyHttpContext,
                ApplicationContext.Current,
                new WebSecurity(dummyHttpContext, ApplicationContext.Current),
                UmbracoConfig.For.UmbracoSettings(),
                UrlProviderResolver.Current.Providers,
                false);
        }

        var serviceTypeProperty = context.Application.Services
            .GetType()
            .GetProperties()
            .SingleOrDefault(x => x.PropertyType == typeof(T));

        if (serviceTypeProperty == null)
        {
            return default(T);
        }

        return (T)serviceTypeProperty
            .GetValue(context.Application.Services);
    }
}

我将此 IGetUmbracoService service 注入控制器并调用:

service.GetService<IContentService>().SaveAndPublishWithStatus(item);

...出现以下错误

System.ArgumentNullException: Value cannot be null. Parameter name: httpContext at System.Web.HttpContextWrapper..ctor(HttpContext httpContext) at Umbraco.Web.SingletonHttpContextAccessor.get_Value() at Umbraco.Web.RequestLifespanMessagesFactory.Get() at Umbraco.Core.Services.ContentService.SaveAndPublishDo(IContent content, Int32 userId, Boolean raiseEvents) at Umbraco.Core.Services.ContentService.Umbraco.Core.Services.IContentServiceOperations.SaveAndPublish(IContent content, Int32 userId, Boolean raiseEvents) at Umbraco.Core.Services.ContentService.SaveAndPublishWithStatus(IContent content, Int32 userId, Boolean raiseEvents)

如何在不使用 frowned upon HttpContext.Current = ... 的情况下模拟 http 上下文?


我假设相关问题来自:

RequestLifespanMessagesFactory.cs

这反过来又调用了这个的实现:

SingletonHttpContextAccessor.cs

我用 Umbraco 做了一些工作,运行 它来自控制台应用程序,然后使用 Umbraco API 调用 Umbraco。 我相信我基于这个项目:https://github.com/sitereactor/umbraco-console-example

可能会有用。

感谢 user369142。这就是最终的工作:

我还必须确保我没有在 SaveandPublish 调用中引发任何事件...因为 HttpContext 期望在上下文中注册消息但我们不会模拟任何...如果您确定raise events 是 false,它会跳过关心那个的代码。

public class CustomSingletonHttpContextAccessor : IHttpContextAccessor
{
    public HttpContextBase Value
    {
        get
        {
            HttpContext context = HttpContext.Current;
            if (context == null)
            {
                context = new HttpContext(new HttpRequest(null, "http://mockurl.com", null), new HttpResponse(null));
            }

            return new HttpContextWrapper(context);
        }
    }
}

public class CustomRequestLifespanMessagesFactory : IEventMessagesFactory
{
    private readonly IHttpContextAccessor _httpAccessor;

    public CustomRequestLifespanMessagesFactory(IHttpContextAccessor httpAccessor)
    {
        if (httpAccessor == null)
        {
            throw new ArgumentNullException("httpAccessor");
        }

        _httpAccessor = httpAccessor;
    }

    public EventMessages Get()
    {
        if (_httpAccessor.Value.Items[typeof(CustomRequestLifespanMessagesFactory).Name] == null)
        {
            _httpAccessor.Value.Items[typeof(CustomRequestLifespanMessagesFactory).Name] = new EventMessages();
        }

        return (EventMessages)_httpAccessor.Value.Items[typeof(CustomRequestLifespanMessagesFactory).Name];
    }
}

public class CustomBootManager : WebBootManager
{
    public CustomBootManager(UmbracoApplicationBase umbracoApplication)
        : base(umbracoApplication)
    {
    }

    protected override ServiceContext CreateServiceContext(DatabaseContext dbContext, IDatabaseFactory dbFactory)
    {
        //use a request based messaging factory
        var evtMsgs = new CustomRequestLifespanMessagesFactory(new CustomSingletonHttpContextAccessor());

        return new ServiceContext(
            new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
            new PetaPocoUnitOfWorkProvider(dbFactory),
            new FileUnitOfWorkProvider(),
            new PublishingStrategy(evtMsgs, ProfilingLogger.Logger),
            ApplicationCache,
            ProfilingLogger.Logger,
            evtMsgs);
    }
}

public class CustomUmbracoApplication : Umbraco.Web.UmbracoApplication
{
    ...
    protected override IBootManager GetBootManager()
    {
        return new CustomBootManager(this);
    }
    ...
}