开发者

silverlight, using Observables on WCF calls, casting IEvent<T> where T : AsyncCompletedEventArgs

i have a question using Observables in Silverlight 4 to make WCF calls. Consider the simple webservice call below.

var adminclient = ServiceProxy.WithFactory<AuthenticationClient>();
var results= Observable.FromEvent<AuthorizeAdministratorCompletedEventArgs>(
   s => adminclient.AuthorizeAdministratorCompleted += s,
   s => adminclient.AuthorizeAdministratorCompleted -= s).ObserveOnDispatcher();

adminclient.AuthorizeAdministratorAsync();
results.Subscribe(e =>
{
   //Enable UI Button
});

i have implemented an extension method, that wraps the subscribe method, it does some error validation on the return.


On the return results.Subscribe(e =>

e is System.Collections.Generic.Event<AuthorizeAdministratorCompletedEventArgs>

almost every query will have a different return type such as:

e is System.Collections.Generic.Event<AsyncCompletedEventArgs>

if i had a wrapper that looked something like this, how can i cast every type 开发者_开发知识库of xxxCompletedEventArgs to its base type AsyncCompletedEventArgs so that i can access e.EventArgs and inspect the Error property

public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext = null, Action onError = null, Action onFinal = null)
{
    Action<TSource> onNextWrapper = (s) =>
    {                   
    var args = (System.Collections.Generic.IEvent<AsyncCompletedEventArgs>)s;

    try
       {                            
          if (WCFExceptionHandler.HandleError(args.EventArgs))
             {
                if (onNext != null)
                   onNext(s);
             }
             else
             {
                if (onError != null)
                   onError();
             }
        }
        finally
        {
           if (onFinal != null)
              onFinal();
        }
   };

   return source.Subscribe<TSource>(onNextWrapper, (e) => { throw e; });
}

The code above will fail

Unable to cast object of type 'System.Collections.Generic.Event1[MyProject.Provider.AuthorizeAdministratorCompletedEventArgs]' to type 'System.Collections.Generic.IEvent1[System.ComponentModel.AsyncCompletedEventArgs]'

This is the method definition of WCFExceptionHandler.HandleError(args.EventArgs))

public static bool HandleError(AsyncCompletedEventArgs e)


I'd probably change you extension method so that it acts to handle the the events as a non blocking operator (much the same as the majority of the Rx extension method operators). Something like:

public static IObservable<IEvent<TEventArgs>> GetHandledEvents<TEventArgs>(this IObservable<IEvent<TEventArgs>> source)
    where TEventArgs : AsyncCompletedEventArgs
{
    return Observable.CreateWithDisposable<IEvent<TEventArgs>>(observer =>
        {
            return source.Subscribe(evt =>
                {
                    try
                    {
                        if (WCFExceptionHandler.HandleError(evt.EventArgs))
                        {
                            observer.OnNext(evt);
                        }
                        else
                        {
                            observer.OnError(new Exception("Some Exception"));
                        }
                    }
                    finally
                    {
                        observer.OnError(new Exception("Some Other Exception"));
                    }
                }, 
                observer.OnError, 
                observer.OnCompleted);
        });
}

Then call it through:

results.GetHandledEvents()
  .Finally(() => DoSomethingFinally())
  .Subscribe(e =>
  {
   //Enable UI Button
  },
  ex => HandleException(ex),
  () => HandleComplete());

I think this should solve your issues as the events will funnel through as their original type and it ensures that HandleError gets event args that are the correct type.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜