IIS远程异常



我有一个IIS应用程序,它引用了一个插件管理器,从一个文件夹中读取所有可用的插件,当它被托管大约5-10分钟后,我开始得到以下异常

[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

我做了一些研究,遇到了ILease和ISponsor,但我不知道如何实现它或它是如何工作的。我现在的代码是这样的,为了清晰起见,我只是删除了部分方法的主体[编辑:添加了方法体]

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远程有点过时了,但我不明白为什么它会成为应用程序域之间通信的问题,所以…

当您创建一个远程对象的新实例时,您实际做的是请求远程端为您创建一个实例,而您只维护一个代理。远程端将每个这样的对象与租约相关联——这描述了如何处理对象的生命周期。这意味着即使客户端仍然有对远程对象的强引用,远程对象也可以在其租约到期时被垃圾收集。

检查是否发生这种情况的最简单方法是使用RemotingServices.GetLifetimeService方法。只需在代理对象上使用它,您就可以获得所需的信息—例如,CurrentState将告诉您远程是否仍处于活动状态。如果是,您也可以使用Renew来延长租期。

因此,处理远程对象生命周期的通常方法是-检查它是否仍然存活;如果是,那就延长租期,做你想做的。确保您也检查了CurrentLeaseTime -这是一个好主意,以保持它的一些合理的值,而不是总是Renew固定的时间。

相关内容

  • 没有找到相关文章

最新更新