Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Terry Clancy 204 posts 944 karma points
    Mar 17, 2017 @ 07:51
    Terry Clancy
    0

    Umbraco MediaService on sperate thread generates an Exception

    Note this has also been posted at http://eureka.ucommerce.net/#!/question/2157/Problem-adding-thousands-of-uCommerce-products-Umbraco-MediaService-on-sperate-thread-generates-an-Exception#top

    Dear Umbraco Folk,

    I have a log running service that creates several thousands of uCommerce products and for most of them it adds a related photo.

    I kick off this process using a web service and because the process runs for over one hour the web API call times out after one hour.

    To address this I call the long running class using Task.Run so it runs on a separate new thread. This works fine except for if I need to add photos.

    Adding Photos as Umbraco Media requires the media service defined as follows

    var mediaService = ApplicationContext.Current.Services.MediaService;

    BUT then some lines that then use this mediaService cause an exception. Some do not . For example the first line below does not and the second line does.

                            IMedia ProductImage_StndrdSize = mediaService.CreateMedia(productImage_StndrdSize_FileName, tTImagesFolderID, "Image");    <<<<< This line works
                            mediaService.Save(ProductImage_StndrdSize);   <<<<< This line causes exception
    

    This only happens when running the method on a separate thread.

    The exception is


    System.ArgumentNullException was unhandled by user code HResult=-2147467261 Message=Value cannot be null. Parameter name: httpContext ParamName=httpContext Source=System.Web StackTrace: at System.Web.HttpContextWrapper..ctor(HttpContext httpContext) at Umbraco.Web.SingletonHttpContextAccessor.getValue() at Umbraco.Web.RequestLifespanMessagesFactory.Get() at Umbraco.Core.Services.MediaService.Umbraco.Core.Services.IMediaServiceOperations.Save(IMedia media, Int32 userId, Boolean raiseEvents) at Umbraco.Core.Services.MediaService.Save(IMedia media, Int32 userId, Boolean raiseEvents) at TeraTastic.TTClasses.TTUCommerceAdmin.TTImportData(RequestTTImportData requestTTImportData, String webSiteRootPhysicalPath) in D:\Clancy\ATeraTastic\Dev\TeraTastic14\TeraTastic\TTClasses\TTUCommerceAdmin.cs:line 3474 at TeraTastic.Controllers.TTUCAdminController.<>cDisplayClass120.0() in D:\Clancy\ATeraTastic\Dev\TeraTastic14\TeraTastic\Controllers\TT_UCAdminController.cs:line 441 at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() InnerException:


    I think the problem is that because I am running the code on a new thread I lose the httpContext I had on the calling thread.

    Assuming this to be the problem (let me know if otherwise) my question becomes:

    Can I, and how can I, run this code on a hew thread when I don't have httpContext ?

    Terry Clancy

    ClanceZ

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    Mar 17, 2017 @ 11:59
    Dan Diplo
    0

    You are right, it's the lack of the underlying HttpContext that causes the issue. I have heard of people faking the context, but not sure if this will work in every instance.

    Here's an example of faking it you might be able to try:

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

  • Terry Clancy 204 posts 944 karma points
    Mar 18, 2017 @ 06:41
    Terry Clancy
    100

    Thank you Dan,

    The solution you suggested did not fix the problem, probably because it fakes UmbracoContext rather than httpContext.

    I did however solve my problem by Faking httpContext based on code from http://stackoverflow.com/questions/28085439/parameter-cannot-be-null-parameter-name-http-context

    Here is my (very similar) code:

    The Helper Class

        public class TT_ContextHelpers
    {
            public static HttpContext CreateHttpContext(HttpRequest httpRequest, HttpResponse httpResponse)
            {
                var httpContext = new HttpContext(httpRequest, httpResponse);
    
                var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
                                                        new HttpStaticObjectsCollection(), 10, true,
                                                        HttpCookieMode.AutoDetect,
                                                        SessionStateMode.InProc, false);
    
                httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
                                            BindingFlags.NonPublic | BindingFlags.Instance,
                                            null, CallingConventions.Standard,
                                            new[] { typeof(HttpSessionStateContainer) },
                                            null)
                                    .Invoke(new object[] { sessionContainer });
    
                return httpContext;
            }
    }
    

    and here is how you use it. In my case I put this are the beginning of the Method I call as a new thread:

                HttpContext.Current = TT_ContextHelpers.CreateHttpContext(
                new HttpRequest("", "http://localhost/", ""),
                new HttpResponse(new StringWriter())
                );
    

    I actually think this is a kind of ugly solution. If anyone has a better approach let me know !!

    Otherwise, I hope this helps folk :-)

    Terry Clancy

    ClanceZ

Please Sign in or register to post replies

Write your reply to:

Draft