Antaris / RazorEngine

Open source templating engine based on Microsoft's Razor parsing engine
http://antaris.github.io/RazorEngine
Other
2.13k stars 576 forks source link

Introduction of CrossAppDomainCleanUp causing issues with non-serializable objects #324

Open madelson opened 8 years ago

madelson commented 8 years ago

One of the recent upgrades to RazorEngine has led us to start seeing errors like the following:

Error message: Type '[some type]' in assembly '[some assembly]' is not marked as serializable.
at System.AppDomain.InternalCreateInstanceFromWithNoSecurity(String assemblyName, String typeName)
at RazorEngine.Compilation.CrossAppDomainCleanUp.InitHelper.CreateHelper()
at RazorEngine.Compilation.ExecutionContextLessThread.CallHelperSafeHelper`2.AsAction()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at RazorEngine.Compilation.ExecutionContextLessThread.DefaultCallFunc[O](Func`1 f)
at RazorEngine.Compilation.CrossAppDomainCleanUp..ctor(AppDomain toWatch, IPrinter printer)
at RazorEngine.Compilation.CrossAppDomainCleanUp.CreateInitial()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at RazorEngine.Compilation.CrossAppDomainCleanUp.RegisterCleanup(String item, Boolean throwOnDefault)
at RazorEngine.Templating.InvalidatingCachingProvider.CacheTemplate(ICompiledTemplate template, ITemplateKey templateKey)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)

In this case "some type" and "some assembly" are a custom identity type we use which is not serializable. While we could try to get the creator of that type to be serializable, I wanted to first understand why this was happening and whether there was anything other than make our code 100% remoting compliant in order to keep upgrading RazorEngine.

EDIT: looking into this more, it seems like it's a resurgence of https://github.com/Antaris/RazorEngine/issues/267, where the ExecutionContextLessThread does not seem to be successfully suppressing the execution context.

matthid commented 8 years ago

Yes this is a bug in RazorEngine, thanks for reporting this. This is releated to https://github.com/Antaris/RazorEngine/issues/275 as well. And the workaround is the same:

config.CachingProvider = new DefaultCachingProvider(t => {});
config.DisableTempFileLocking = true;

Can you provide a simplified repro for this (Or at least show me how you implemented your custom identity type)? It is really weird because we try to start a new thread for the sole purpose to get a 'clean' ExecutionContext (so there is nothing to serialize). However, some things seem to slip through. I'm starting to think that this is some WinAPI specific thing, where the context is saved within the (windows-)thread itself and not the '.net' ExecutionContext.

madelson commented 8 years ago

I don't have a small repro handy, but here are some details that might be relevant.

NicoJuicy commented 8 years ago

Had the same bug with a custom implementation of IIdentity

config.CachingProvider = new DefaultCachingProvider(t => {});
config.DisableTempFileLocking = true;

Fixed it. Thanks!

matthid commented 8 years ago

Any code sample (ideally simplified) reproducing the problem would be appreciated. I already tried fixing that "blindly" but no approach seems to fetch all cases.

cysnet commented 5 months ago

@matthid This error occurs if I use CallContext.LogicalSetData before method IsolatedRazorEngineService.Create() and set an entity that is not marked [Serializable].

here is a demo to produce this error.

using RazorEngine.Templating;
using System.Runtime.Remoting.Messaging;

namespace WorkerRole
{
    public class User
    {
        public string Name { get; set; }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            var user = new User();
            CallContext.LogicalSetData("123", user);
            using (var service = IsolatedRazorEngineService.Create())
            {
            }
        }
    }
}

error is

System.Runtime.Serialization.SerializationException: 'Type 'WorkerRole.User' in assembly 'WorkerRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.'
cysnet commented 5 months ago

I create a new issue to track this problem.

https://github.com/Antaris/RazorEngine/issues/601