microsoft / service-fabric-services-and-actors-dotnet

Reliable Services and Reliable Actors are Service Fabric application frameworks for building highly-scalable distributed cloud applications.
Other
268 stars 115 forks source link

System.Runtime.Serialization.SerializationException: 'Type 'Microsoft.ServiceFabric.Services.LogContext' in assembly 'Microsoft.ServiceFabric.Services, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.' #350

Open LastTribunal opened 1 year ago

LastTribunal commented 1 year ago

Describe the bug started happening sometime since version 6.0.1048 Probably when Microsoft.ServiceFabric.Services.LogContext was added

yashagarwal23 commented 1 year ago

Thank you @LastTribunal for letting us know. Looking into it.

yashagarwal23 commented 1 year ago

@LastTribunal can you please describe your use case? As in when do you see this exception? Just wanted to know what all scenarios are affected. Thanks.

LastTribunal commented 8 months ago

its real simple, you added a new class Microsoft.ServiceFabric.Services.LogContext and didnt make it serializable, which broke my code when I upgraded the binaries for SF 10 (mandatory) I am running a Marshal process


using Newtonsoft.Json;
using System;
using System.IO;
using System.Runtime.Remoting.Lifetime;
using System.Security.Permissions;
using System.Xml;
using System.Xml.Xsl;

namespace MarshalProcessors
{
    public class XsltProcessor : MarshalByRefObject
    {
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
        public override object InitializeLifetimeService()
        {
            var lease = (ILease)base.InitializeLifetimeService();
            if (lease?.CurrentState != LeaseState.Initial) return lease;
            lease.InitialLeaseTime = TimeSpan.FromMinutes(10);
            lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
            lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
            return lease;
        }

        [LoaderOptimization(LoaderOptimization.MultiDomain)]
        public string GetString(string xmlDoc = null, string xsltDoc = null)
        {
            if (xsltDoc == null || xmlDoc == null) return null;
            var xsl = JsonConvert.DeserializeXmlNode(xsltDoc);
            var xml = new XmlDocument();
            xml.LoadXml(xmlDoc);
            var xslArg = new XsltArgumentList();

            xslArg.AddExtensionObject("urn:methods", new Methods());
            var settings = new XsltSettings { EnableScript = true };

            var xslt = new XslCompiledTransform(false);
            xslt.Load(xsl ?? throw new InvalidOperationException(), settings, null);
            using (var sw = new StringWriter())
            {
                using (var xwo = XmlWriter.Create(sw, xslt.OutputSettings))
                    xslt.Transform(xml, xslArg, xwo);
                return sw.ToString();
            }
        }
    }
}
olegsych commented 4 weeks ago

LogContext is not serializable by design. The code example doesn't explain why it could be a problem. Please expand the example and reopen the issue if you have a legitimate reason for this requirement.

LastTribunal commented 3 weeks ago

you broke something that used to work, yes that by design per MS, which is inline with the narrative that a man can be a woman.. enjoy

olegsych commented 3 weeks ago

@LastTribunal I am guessing that you are serializing an object graph that now includes the new LogContext class, but I can't see that from your example. Can you expand the example to illustrate how Service Fabric is involved?

LastTribunal commented 3 weeks ago

Конечно, Олег.

I didnt make it clear, I'll try now.. The service class I showed you uses an XSLT transformer that doesn't dispose of memory resulting from JS processing that is part of the XSLT document. To clear the memory, I came up with the "rotating app domain", where I create enqueue dequeue and dispose of app domains every 3 minutes, this solution has been working until the LogContext class was added or if it was there, it is no longer marked serializable, since after later releases, this mechanism throws the aforementioned error. Here is the code I used to create and app domain from the xslt class shown above.. Which is another SF service. If you still have questions, we can do a screenshare over teams, and Ill be happy to explain further..

using System;

namespace Presenter.Service
{
    public sealed class Isolated<T> : IDisposable where T : MarshalByRefObject
    {
        private AppDomain _domain;
        public T Value { get; }

        public Isolated()
        {
            _domain = AppDomain.CreateDomain(Guid.NewGuid().ToString(),
                null, AppDomain.CurrentDomain.SetupInformation);

            var type = typeof(T);

            Value = (T)_domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName ?? string.Empty);
        }

        public void Dispose()
        {
            if (_domain == null) return;
            AppDomain.Unload(_domain);

            _domain = null;
        }
    }
}
olegsych commented 3 weeks ago

Thanks @LastTribunal. Are you using .NET remoting or Service Fabric remoting to create instances of Isolated<XsltProcessor> and invoke the GetString method? Is that when you're getting the SerializationException about LogContext? Is the exception thrown on the client or the server side? Could you share the stack trace(s)?