Исключение" объект отключен или не существует на сервере"
Мне нужно использовать перекрестные вызовы appdomain в моем приложении, и иногда у меня есть это RemotingException:
Object '/2fa53226_da41_42ba_b185_ec7d9c454712 / ygiw+xfegmkhdinj7g2kpkhc_7.Рэм был отключен или не существует на сервере.
объект все еще жив, я проверил.
UPD я установил точку останова в финализаторе целевого объекта, и он никогда не попадает. Таким образом, этот объект жив и не был уничтожен.
5 ответов
Это, вероятно, потому, что локальный сборщик мусора на стороне сервера собирает объект. Вы можете предотвратить это, возобновив лизинг. Подробнее об этом читайте в следующих статьях:
- управление временем жизни удаленных объектов .NET с лизингом и спонсорством
- CLR Inside Out: управление временем жизни объекта
обновление: к сожалению, журнал MSDN выпускается с 2008 года или старше больше не просматриваются в интернете, а только как .chm-файлы, которые необходимо загрузить на локальную машину. Предыдущие вопросы можно найти в:
- управление временем жизни удаленных объектов .NET с лизингом и спонсорством в выпуск за декабрь 2003 года
- CLR Inside Out: управление временем жизни объекта в ноябрь 2007 года выпуска
это происходит потому, что управление временем жизни на стороне сервера отключает объект, когда его аренда истекает, чтобы позволить GC собрать его. Если вы попытаетесь использовать его со стороны клиента, вы получите исключение, даже если он еще не был GC'D на сервере (например, потому что на него все еще есть другая ссылка), но срок аренды истек. Это делается для того, чтобы избежать непредсказуемого поведения. Принятый ответ дает хорошую ссылку на то, как правильно управлять временем жизни удаленного .NET Объекты.
у меня была та же проблема, и я искал много часов с помощью многих сообщений StackOverflow.
я, наконец, нашел полную проблему.
- Я должен использовать спонсора для поддержания моего MarshalByRefObject живым.
- у меня тогда была та же проблема, что и @user626528 : объект жив, но у меня было исключение. На самом деле,мне нужно было "спонсировать" все "TransparentProxy" экземпляров, и не только главный: мой главный объект созданный в песочнице (другой AppDomain) возвращает ссылки на другие MarshalByRefObjects.
вот полное объяснение и пример использования :
мой класс "Loader" наследуется от MarshalByRefObject, и я поддерживаю его с классом ISponsor. Я знаю, что "ClientSponsor" существует в .NET, но у меня не было возможности определить, вызывается ли и когда Renewal (), поэтому я сделал свой класс с помощью сообщества StackOverflow (читайте комментарии к коду):
/// <see cref="https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called"/>
public class RemotingSponsor : MarshalByRefObject, ISponsor, IDisposable
{
/*
* @CoryNelson said :
* I've since determined that the ILease objects of my sponsors
* themselves are being GCed. They start out with the default 5min lease
* time, which explains how often my sponsors are being called. When I
* set my InitialLeaseTime to 1min, the ILease objects are continually
* renewed due to their RenewOnCallTime being the default of 2min.
*
*/
ILease _lease;
public RemotingSponsor(MarshalByRefObject mbro)
{
_lease = (ILease)RemotingServices.GetLifetimeService(mbro);
if (_lease == null) throw new NotSupportedException("Lease instance for MarshalByRefObject is NULL");
_lease.Register(this);
}
public TimeSpan Renewal(ILease lease)
{
Debug.WriteLine("RemotingSponsor.Renewal called");
return this._lease != null ? lease.InitialLeaseTime : TimeSpan.Zero;
}
public void Dispose()
{
if (_lease != null)
{
_lease.Unregister(this);
_lease = null;
}
}
public override object InitializeLifetimeService()
{
/*
*
* @MatthewLee said:
* It's been a long time since this question was asked, but I ran into this today and after a couple hours, I figured it out.
* The 5 minutes issue is because your Sponsor which has to inherit from MarshalByRefObject also has an associated lease.
* It's created in your Client domain and your Host domain has a proxy to the reference in your Client domain.
* This expires after the default 5 minutes unless you override the InitializeLifetimeService() method in your Sponsor class or this sponsor has its own sponsor keeping it from expiring.
* Funnily enough, I overcame this by returning Null in the sponsor's InitializeLifetimeService() override to give it an infinite timespan lease, and I created my ISponsor implementation to remove that in a Host MBRO.
* Source: https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called
*/
return (null);
}
}
и тогда я использовал этот "пользовательский спонсор" выглядит так:
// Loader and Container for MarshalByRefObject in another domain
public class PluginFile : IDisposable
{
private RemotingSponsor _sponsor; // Keep instance not to have Sponsor Garbage Collected
private AppDomain _sandbox;
private ICustomPlugin[] _plugins; // I do not store real instances of Plugins, but a "CustomPluginProxy" which is known both by main AppDomain and Plugin AppDomain.
// Constructor : load an assembly file in another AppDomain (sandbox)
public PluginFile(System.IO.FileInfo f, AppDomainSetup appDomainSetup, Evidence evidence)
{
Directory = System.IO.Path.GetDirectoryName(f.FullName) + @"\";
_sandbox = AppDomain.CreateDomain("sandbox_" + Guid.NewGuid(), evidence, appDomainSetup);
_sandbox.Load(typeof(Loader).Assembly.FullName);
// - Instanciate class "Loader" INSIDE OTHER APPDOMAIN, so we couldn't use new() which would create in main AppDomain.
_loader = (Loader)Activator.CreateInstance(
_sandbox,
typeof(Loader).Assembly.FullName,
typeof(Loader).FullName,
false,
BindingFlags.Public | BindingFlags.Instance,
null,
null,
null,
null).Unwrap();
// - Load plugins list for assembly
_plugins= _loader.LoadPlugins(f.FullName);
// - Keep object created in other AppDomain not to be "Garbage Collected". I create a sponsor. The sponsor in registed for object "Lease". The LeaseManager will check lease expiration, and call sponsor. Sponsor can decide to renew lease. I not renewed, the object is garbage collected.
// - Here is an explanation. Source: https://stackoverflow.com/questions/12306497/how-do-the-isponsor-and-ilease-interfaces-work
_sponsor = new RemotingSponsor(_loader);
// Here is my SOLUTION after many hours ! I had to sponsor each MarshalByRefObject (plugins) and not only the main one that contains others !!!
foreach (ICustomPlugin plugin in Plugins)
{
ILease lease = (ILease)RemotingServices.GetLifetimeService((PluginProxy)plugin);
lease.Register(_sponsor); // Use the same sponsor. Each Object lease could have as many sponsors as needed, and each sponsor could be registered in many Leases.
}
}
}
тип PluginProxy имеет ссылку на реальный тип плагина. Действительно, PluginProxy создается внутри плагина AppDomain и возвращается в main AppDomain, чтобы позволить ему вызывать Плагины, даже если он игнорирует их реальный тип. Таким образом, PluginProxy, чтобы быть доступным из основного AppDomain, должен быть сериализован для пересечения пределов AppDomains. У меня была проблема, потому что я не спонсировал эти MarshalByRefObject (ы) :
/// <see cref="https://stackoverflow.com/questions/4185816/how-to-pass-an-unknown-type-between-two-net-appdomains"/>
[Serializable]
public class PluginProxy : MarshalByRefObject, ICustomPlugin
{
private ICustomPlugin _hostedPlugin;
/// <summary>
/// Parameterless constructor for deserialization
/// </summary>
public PluginProxy()
{
}
~PluginProxy()
{
Debug.WriteLine("DESTRUCTOR ~PluginProxy");
}
/// <summary>
/// Constructor reserved from real Plugin type
/// </summary>
/// <param name="name"></param>
public PluginProxy(ICustomPlugin hostedPlugin)
{
_hostedPlugin = hostedPlugin;
}
public PluginName Name => _hostedPlugin.Name;
public PluginResult Execute(PluginParameters parameters, PluginQuery query)
{
return(_hostedPlugin.Execute(parameters, query));
}
}
Это было сложно решить кучу проблем, надеюсь, это поможет !
ссылки:
- MSDN:интерфейс ILease
- MSDN:класс ObjRef
- Microsoft:как маршалировать объект на удаленный сервер по ссылке с помощью Visual C#
StackOverflow:удаленный спонсор перестает называться
StackOverflow:как сделать Интерфейсы ISponsor и ILease работают?
- StackOverflow:как передать неизвестный тип между двумя .NET AppDomains?
- StackOverflow:AppDomain и MarshalByRefObject время жизни: как избежать RemotingException?
- StackOverflow:MarshalByRefObject становится "отключен на сервере" даже при спонсировании
в моем случае проблема заключалась в том, что на клиентском компьютере был активен виртуальный сетевой адаптер, отключив виртуальные сетевые адаптеры, проблема была решена
в моем случае это происходило с SQL LocalDB, хранящимся в внутри . Всякий раз, когда я пытаюсь использовать консоль пакета для запуска update-database
для инициализации базы данных Entity Framework с помощью миграции ничего не происходит. Затем через некоторое время я получаю эту ошибку.
Я решил это, изменив права доступа к файлам на App_Data
. После исправления, вуаля, это сработало.