Ответ 1
Мы столкнулись с этой же проблемой и пошли на упомянутый вами подход к домену приложений, реализуя решение, основанное на том, что предлагается здесь, что является действительно хорошей записью о том, как управлять выполнением кода в отдельном домене приложения
Мы используем его изолированный класс в значительной степени, как есть:
public sealed class Isolated<T> : IDisposable where T : MarshalByRefObject
{
private AppDomain _domain;
private readonly T _value;
public Isolated()
{
_domain = AppDomain.CreateDomain("Isolated:" + Guid.NewGuid(), null, AppDomain.CurrentDomain.SetupInformation);
var type = typeof(T);
_value = (T)_domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
}
public T Value
{
get
{
return _value;
}
}
public void Dispose()
{
if (_domain == null) return;
AppDomain.Unload(_domain);
_domain = null;
}
}
И тогда у нас есть обертка вокруг стандартного WebClient, который позволяет установить протокол:
public class WebClient : MarshalByRefObject, IWebClient
{
public WebClientResponse GetResponse(string address)
{
return GetResponse(address, null);
}
public WebClientResponse GetResponse(string address, string securityProtocol)
{
if (!string.IsNullOrWhiteSpace(securityProtocol))
ServicePointManager.SecurityProtocol = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), securityProtocol);
var response = new WebClientResponse();
try
{
using (var wc = new System.Net.WebClient())
{
// <do stuff>
}
}
catch (Exception ex)
{
response.Exception = new GetResponseException(string.Format("Unable to get response from {0}", address), ex);
}
return response;
}
}
[Serializable]
public class WebClientResponse
{
public Exception Exception { get; set; }
public string Response { get; set; }
}
[Serializable]
public class GetResponseException : Exception
{
public GetResponseException(string message, Exception innerException)
: base(message, innerException)
{
}
public GetResponseException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
Связывая их вместе, у нас есть код, который определяет, нужно ли ему переопределять установленный в настоящее время протокол. Если это так, он закручивает изолированный домен приложения, если он не использует существующий WebClient:
...
WebClientResponse webClientResponse;
if (!string.IsNullOrWhiteSpace(ForceSecurityProtocol))
{
using (var isolated = new Isolated<WebClient>())
{
webClientResponse = isolated.Value.GetResponse(url, ForceSecurityProtocol);
}
}
else
{
webClientResponse = _webClient.GetResponse(url);
}
...
Обратите внимание, что наше использование не в чрезвычайно высокой пропускной способности нашего приложения, поэтому любая цена исполнения, которую мы платим, используя этот подход, действительно не влияет. Если бы мы собирались сделать что-то подобное в месте, где это было на пути значительного объема трафика через наше веб-приложение, мы бы провели некоторое тестирование.