简体   繁体   中英

IIS Remote Exception

I have an IIS Application which references a plugin manager which reads all available plugins from a folder, when it is hosted after about 5-10 minutes I start getting the following Exception

[RemotingException: Object '/1608465e_9d80_4b40_be20_4c96904643e0/wizi+0g5od5gwmunm_indiws_253.rem' has been disconnected or does not exist at the server.]
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +14416170
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +388
PluginManager.Core.Interfaces.IPluggin.get_Id() +0
PluginManager.PluginDetails.get_Id() +27

I did some research and came accross ILease and ISponsor but I have no Idea how to implement it or how it works. My current code as it is at this moment, I just removed parts the body of the methods for clarity [Edit : added the method bodies]

public class AssemblyReflectionProxy : MarshalByRefObject
{
    private string _assemblyPath;

    public AssemblyReflectionProxy()
    {
        Id = "";
    }

    public void LoadAssembly(String assemblyPath)
    {
        try
        {
            _assemblyPath = assemblyPath;
            Assembly.ReflectionOnlyLoadFrom(assemblyPath);
        }
        catch (FileNotFoundException)
        {
        }
    }

    public TResult Reflect<TResult>(Func<Assembly, TResult> func)
    {
        var directory = new FileInfo(_assemblyPath).Directory;
        ResolveEventHandler resolveEventHandler = (s, e) => OnReflectionOnlyResolve(e, directory);
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += resolveEventHandler;
        var assembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault(a => String.Compare(a.Location, _assemblyPath, StringComparison.Ordinal) == 0);
        var result = func(assembly);
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= resolveEventHandler;

        return result;
    }

    public T GetEntryType<T>()
    {
        var directory = new FileInfo(_assemblyPath).Directory;
        ResolveEventHandler resolveEventHandler = (s, e) => OnReflectionOnlyResolve(e, directory);
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += resolveEventHandler;
        var assembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault(a => string.Compare(a.Location, _assemblyPath, StringComparison.Ordinal) == 0);
        if (assembly != null)
        {
            var result = assembly.GetTypes();
            var type = result.FirstOrDefault(x => x.GetInterface(typeof(T).Name) != null);
            if (type != null)
            {
                var remoteObject = AppDomain.CurrentDomain.CreateInstanceFrom(type.Assembly.Location, type.FullName);                   
                var obj = remoteObject.Unwrap();
                AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= resolveEventHandler;
                return (T)obj;
            }
        }
        return default(T);
    }

    private Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
    {
        var loadedAssembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault(asm => string.Equals(asm.FullName, args.Name, StringComparison.OrdinalIgnoreCase));

        if (loadedAssembly != null)
        {
            return loadedAssembly;
        }

        var assemblyName = new AssemblyName(args.Name);
        var dependentAssemblyFilename = Path.Combine(directory.FullName, assemblyName.Name + ".dll");

        if (File.Exists(dependentAssemblyFilename))
        {
            return Assembly.ReflectionOnlyLoadFrom(dependentAssemblyFilename);
        }
        return Assembly.ReflectionOnlyLoad(args.Name);
    }

    private string Id { get; set; }
    internal string GetId()
    {
        if (String.IsNullOrEmpty(Id))
        {
            var fileBytes = File.ReadAllBytes(_assemblyPath);
            var hash = Convert.ToBase64String(fileBytes).GetHashCode();
            var bytes = BitConverter.GetBytes(hash);
            StringBuilder sb = new StringBuilder();
            foreach (byte b in bytes)
                sb.Append(b.ToString("X2"));
            Id = sb.ToString();
        }
        return Id;
    }
}


public sealed class AssemblyManager : MarshalByRefObject, IDisposable
{
    private readonly Dictionary<string, AppDomain> _assemblyDomains = new Dictionary<string, AppDomain>();
    readonly Dictionary<string, AssemblyReflectionProxy> _proxies = new Dictionary<string, AssemblyReflectionProxy>();
    public AssemblyManager()
    {

    }

    public string LoadAssembly(string assemblyPath)
    {
        var fileInfo = new FileInfo(assemblyPath);
        var name = fileInfo.Name.Replace(".dll", "");
        if (fileInfo.Exists)
        {
            if (!_assemblyDomains.ContainsKey(name))
            {
                var appDomain = CreateChildDomain(AppDomain.CurrentDomain, fileInfo.Name);
                _assemblyDomains[name] = appDomain;
                try
                {
                    Type proxyType = typeof(AssemblyReflectionProxy);
                    {
                        var proxy = (AssemblyReflectionProxy)appDomain.CreateInstanceFrom(proxyType.Assembly.Location, proxyType.FullName).Unwrap();
                        proxy.LoadAssembly(assemblyPath);
                        _proxies[name] = proxy;
                        return name;
                    }
                }
                catch
                { }
            }
            else
            {
                return name;
            }
        }
        return "";
    }

    public void Unload()
    {

    }

    private AppDomain CreateChildDomain(AppDomain parentDomain, string domainName)
    {
        var evidence = new Evidence(parentDomain.Evidence);
        var setup = parentDomain.SetupInformation;
        return AppDomain.CreateDomain(domainName, evidence, setup);
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~AssemblyManager()
    {
        Dispose(false);
    }

    public IPluggin GetEntryPluggin(string name)
    {
        IPluggin plugin = default(IPluggin);
        if (_proxies.ContainsKey(name))
        {
            plugin = _proxies[name].GetEntryType<IPluggin>();
        }
        return plugin;
    }

    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            foreach (var appDomain in _assemblyDomains.Values)
                AppDomain.Unload(appDomain);
            _assemblyDomains.Clear();
        }
    }

    internal string GetEntryPlugginID(string name)
    {
        string Id = "";
        if (_proxies.ContainsKey(name))
        {
            Id = _proxies[name].GetId();
        }
        return Id;
    }
}

My Interface is

public interface IPluggin
{
    string Name { get; }
    string Version { get; }
    string Id { get; }
    void Initialize();
    string[] GetElements();
    void SaveSettings(string settings);
    void SetBasePath(string path);
}

.NET remoting is kind of deprecated, but I don't see why it would be a problem for communicating between application domains, so...

When you create a new instance of a remoting object, what you actually do is request the remote side to create one for you, while you only maintain a proxy. The remote side associates each of such objects with a lease - something that describes how the lifetime of the object is handled. This means that even if the client side still has strong references to the remote object, the remote object can be garbage collected when its lease expires.

The easiest way to check if this happened is using the RemotingServices.GetLifetimeService method. Just use it on the proxy object, and you will get the information you need - for example, CurrentState will tell you if the remote is still alive. If it is, you can also extend the lease using Renew .

So, the usual way to handle the lifetime of the remote object would be - check if it is still alive; if it is, extend the lease and do whatever you want. Make sure you check CurrentLeaseTime too - it's a good idea to maintain it some reasonable value, rather than always Renew ing a fixed amount of time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM