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 6x 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

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies