C #: песочница и производительность (MarshalByRefObject) - PullRequest
2 голосов
/ 12 июня 2011

Я написал очень простой веб-сервер на C #, который загружает пользовательские модули, которые обрабатывают запросы к определенному имени домена, как указано в файле конфигурации.Пользовательские модули загружаются в новый домен приложений, потому что мне нужна возможность их динамической выгрузки (тоже хорошо для безопасности).Поскольку модули загружаются в новый домен приложений, все параметры и типы возвращаемых значений - MarshalByRefObject.Это работает нормально, и я передаю объект HttpRequest, который наследуется от MarshalByRefObject, и возвращаю LinkedList, который отправляется обратно клиенту веб-сервером.

Все это работает хорошо, но большая часть данных передается какbyte [], и я полагаю, что прокси-сервер для MarshalByRefObject скопирует все байты из нового AppDomain в основной AppDomain вместо прямого доступа к ним.Итак, если я прав в этом, если один из модулей отправит файл 5 МБ в качестве ответа, тогда 5 МБ будет загружено / сгенерировано в модуле, затем скопировано из модуля AppDomain в основной AppDomain и, наконец, отправлено через сокетназад к клиенту.

Итак, мой вопрос: могу ли я как-то обойти это, чтобы он не копировал столько данных между AppDomain?Или есть лучший способ сделать это, не используя MarshalByRefObject?

Ответы [ 3 ]

3 голосов
/ 12 июня 2011

Строки для каждого процесса, а не для домена приложения (по соображениям производительности).Если html / xml передаются (а не двоичные данные), вы можете изменить свой API для использования Strings вместо byte [].Возможно, вы даже сможете поддерживать строки в общем случае и byte [] в двоичных случаях.

2 голосов
/ 13 июня 2011

В итоге я передал SocketInformation в новый домен приложений и создал там новый объект сокета (в новом домене приложений).

В моем «объекте-обертке из песочницы» у меня есть эта функция:

internal class Sandbox
{
    private AppDomain _AppDomain;
    private WebApplicationProxy _Proxy;

    public Sandbox(string assemblyFile)
    {
        _AppDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
        _Proxy = (WebApplicationProxy)_AppDomain.CreateInstanceAndUnwrap(
                                                    Assembly.GetExecutingAssembly().FullName,
                                                    "WebServer.WebApplication.Proxy");
        _Proxy.Initialize(assemblyFile);
    }
    public void SendResponse(Socket client, HttpRequest request)
    {
        SocketInformation clientInfo = client.DuplicateAndClose(Process.GetCurrentProcess().Id);
        _Proxy.GetResponse(clientInfo, request);
    }
}

И в новом AppDomain «возобновляет» сокет, я пока не уверен, что на самом деле происходит за кулисами ... вот код:

internal class Proxy : MarshalByRefObject
{
    private AppController _AppController;

    public void Initialize(string assemblyFile)
    {
        Assembly asm = Assembly.LoadFile(assemblyFile);
        var q = from t in asm.GetTypes()
                where t.GetInterfaces().Contains(typeof(AppController))
                      && !t.IsAbstract && t.IsClass
                select t;
        foreach (Type t in q)
        {
            _AppController = (AppController)Activator.CreateInstance(t);
        }
    }

    public void SendResponse(SocketInformation clientInfo, HttpRequest req)
    {
        Socket client = new Socket(clientInfo);

        LinkedList<byte[]> toSend = _AppController.GetResponse(client, req);

        foreach (byte[] bytes in toSend)
            client.Send(bytes);

        client.Close();
    }
}

Я не уверен в деталях того, что происходит при вызове DuplicateAndClose или создании нового объекта Socket в новом домене, но пока он работает хорошо.

1 голос
/ 13 июня 2011

Если это .NET 4.0, можно ли использовать файл с отображенной памятью вариант?

...