C#, Асинхронные remote вызовы

6yrop

Как сейчас на дотнете делают асинхронные remote вызовы между .NET->.NET. То что предлагается в WCF-е – кодогенерация и event-ы — мне не нравится, сильно громоздко, плохо управляемо. Да и вообще с WCF не хочется связываться.
Собственно чего хочется. Определяем интерфейс IRemoteFacade, кладем его в сборку, на которую ссылается и сервер и клиент. На сервере делаем его имплементацию RemoteFacadeImpl. А на клиенте дергаем методы интерфейса IRemoteFacade. Удаленные вызовы и асинхронность должны обеспечиваться инфраструктурой.
P.S. да, C# 5.0 еще не вышел.

zorin29

Делаю через WCF. Да, мне бы больше понравилось, если бы была общая сборка с общими типами вместо генерированного кода клиента.
Я не очень понимаю, чем тебя не устраивают event-ы. Как ты хочешь реализовывать асинхронность без event-ов, инфраструктурой?

6yrop

Как ты хочешь реализовывать асинхронность без event-ов
вместо event-ов вполне достаточно простого делегата(лямбды) в аргументе метода. Вот близки к идеальному варианту GWT, из неприятностей остается только дублирование *Async интерфейса.

zorin29

Да, действительно, делегат бы помог. Сам же так пишу на JS, а на C# не распространил идею :)
Вероятно, можно написать простенький helper, который на базе background worker-а делает то, что ты хочешь из синхронного вызова.
Но в тему треда - мне кажется, у MS нет более удобного, чем WCF, подхода.

Bibi

делегаты. лямбды.
КОЛЛБЭК!

6yrop

В общем, на коленке, используя либу Castle.DynamicProxy, вот что получилось:
использование:

RemoteExecuter.Execute(
facade => facade.Method1(1, 2
result => Console.WriteLine(result)
);

реализация:

public static class RemoteExecuter
{
public static void Execute<TResult>(Func<IRemoteFacade, TResult> func, Action<TResult> action)
{
func(ProxyCreator.CreateInterfaceProxy<IRemoteFacade>(new Interceptor<TResult>(action;
}

private class Interceptor<TResult> : IInterceptor
{
private readonly Action<TResult> action;

public Interceptor(Action<TResult> action)
{
this.action = action;
}

public void Intercept(IInvocation invocation)
{
var backgroundWorker = new BackgroundWorker;
backgroundWorker.DoWork +=
(sender, doWorkEventArgs) =>
{
var result = ProcessBytes(SharedUtil.Serialize(new object[] {invocation.Method.Name, invocation.Arguments};
doWorkEventArgs.Result = result == null ? null : SharedUtil.Deserialize(result);
};
backgroundWorker.RunWorkerCompleted +=
(sender, completedEventArgs) => actionTResult) completedEventArgs.Result);
backgroundWorker.RunWorkerAsync;

invocation.ReturnValue = default(TResult);
}

private static byte[] ProcessBytes(byte[] bytes)
{
//здесь пересылаем байты туда и обратно
}
}
}

public static class ProxyCreator
{
public static T CreateInterfaceProxy<T>(IInterceptor interceptor)
{
return Cache<T>.Func(interceptor);
}

private static class Cache<T>
{
public readonly static Func<IInterceptor, T> Func;

static Cache
{
var options = ProxyGenerationOptions.Default;
var type = new DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(typeof(T new Type[0], options);
Func =
interceptor =>
{
return (T)Activator.CreateInstance(
type,
new List<object>(options.MixinData.Mixins) { new[] { interceptor }, new object }.ToArray;
};
}
}
}

agaaaa

Да, мне бы больше понравилось, если бы была общая сборка с общими типами вместо генерированного кода клиента.
Так для этого же есть ChannelFactory<TChannel>.CreateChannel

6yrop

Так для этого же есть ChannelFactory<TChannel>.CreateChannel
я специально же вынес в заголовок "Асинхронные".
Для асинхронных вызовов через ChannelFactory все равно интерфейс кодогенеренный, причем его не удобно использовать: на элементарный вызов пара лишних шагов в том числе каст. Короче, не для людей.
Оставить комментарий
Имя или ник:
Комментарий: