CSLA for WinRT : Getting exceptions when awaiting DataPortal.FetchAsync

CSLA for WinRT : Getting exceptions when awaiting DataPortal.FetchAsync

Old forum URL: forums.lhotka.net/forums/t/11428.aspx


Nilzor posted on Monday, June 25, 2012

Hi, I've just started playing around with the WinRT-build of CSLA. I've been working somewhat with CSLA.NET previously, so I'm familiar with the basic concepts.

Now what happens is that when I call DataPortal.FetchAsync<MyObject>("someParameter"), I get the following exception:

There was no endpoint listening at http://localhost:2114/WcfPortal.svc that could accept the message.
InnerException: No connection could be made because the target machine actively refused it 127.0.0.1:2114

I'm making the assumtion that the dataportal is attempting to set up a WCF client-server for the dataportal. First of all, can I avoid that? It seems like an unneccessary overhead when I'm running both the client and server locally. I thought maybe I could add the [RunLocal] attribute, but it seems not to exist in CSLA.WinRt?

If I have to go with the WCF-method, then I'd like to know why I'm getting the exception. I thought at first it had something to do with permissions, but I have enabled "Internet (Client & Server)" in the appxmanifest-file.

Help appreciated

 

 

 

 

 

JonnyBee replied on Monday, June 25, 2012

Hi Frode,

What type of server accees do you need? You may run local only but you can only interact with web/rest/json services.

The Exception indicates that your serverside DataPortal is not started or the client is miscononfigured..

 

 

Nilzor replied on Monday, June 25, 2012

"My server" a one of Google's services. The application I'm developing is a pure front-end against Google. JSON requests will fire from the client. I don't see why I would need a client-server architecture locally.

JonnyBee replied on Monday, June 25, 2012

Try this instead:

 DataPortal.FetchAsync<MyObject>("someParameter", DataPortal.ProxyModes.LocalOnly)

Tells the dataportal to use local mode (just as in Silverlight). .

Nilzor replied on Monday, June 25, 2012

I'm afraid that did not help. Same result. I could post some test code tomorrow.

DataPortal.FetchChild works though... It always runs locally, right? But I would really like to use the Factory-pattern.

JonnyBee replied on Monday, June 25, 2012

Ok, if you can post some test code then I will look into it.

RockfordLhotka replied on Monday, June 25, 2012

The exception indicates that you either don't have a server-side data portal endpoint set up, or that it isn't reachable.

First, the endpoint must be a Silverlight data portal endpoint, not a .NET endpoint. When you set up and configure the data portal server, you should follow the instructions for setting up a Silverlight server endpoint.

Second, for testing the server is localhost (based on your post). Callbacks to localhost from a WinRT app are normally blocked, but Visual Studio does unblock them on your dev workstation (in the RC). So it shouldn't be a problem to do this unless VS12 was unable to unblock localhost for your app.

RockfordLhotka replied on Monday, June 25, 2012

I should also point out that the local data portal isn't tested yet. Therefore it is possible that the async methods are ignoring the LocalOnly parameter. I thought I got that right, but maybe not.

The reason the local data portal is untested, is that I'm probably going to change the way the local data portal methods are implemented for Silverlight (and therefore also WinRT) so the DataPortal_XYZ methods don't get a callback parameter.

The callback parameter is required for the event-based model used by Silverlight and WP7, but it is not ideal. With the new async support used in CSLA 4.5 I should be able to get rid of that parameter in the DataPortal_XYZ methods. If you want your method to be async, you should make it async and use the await keyword to make your async call in your code.

This won't break any WinRT apps (because there aren't any), and I don't think all that many people use the local data portal in Silverlight - at least not extensively. So for Silverlight users this will be a breaking change, but hopefully a worthy one, and one that doesn't have major impact for most apps.

 

Nilzor replied on Tuesday, June 26, 2012

I'm not exactly sure I understand what the LocalOnly-parameter is supposed to do. Do I still need to configure  a localhost WCF server as described in the CSLA for Silverlight documentation? I was under the impression I bypassed the entire WCF-stuff With LocalOnly. At leas that's what I'd like to achieve.

I have created a sample solution for Win8 RP using CSLA 4.5 here which highlights the exception I'm getting : download link

I'm also confused that you say that you're going to implement DataPortal_XYZ Methods not to get a callback parameter. Haven't you already done that in CSLA 4.5? :) The FetchAsync-method does indeed return an awaitable Object, and does not take a callback parameter.

JonnyBee replied on Tuesday, June 26, 2012

Hi Frode,

Fix checked in to repository - get latest version and try again.

For some reason the Compiler selected overloads that used ProxyMode as UserState and not as ProxyMode. Added explicit null as UserState to make Compiler select correct version.

Nilzor replied on Tuesday, June 26, 2012

Rockford: Ok I understand. Thanks for the explanation. I understand that the WinRT-build of CSLA still is in an early phase.

Jonny: Your fix seemd to work! ...but a new problem arose: Now the task freezes upon the "await". Deadlock of some sort? The Fetch()-method of my factory executes successfully, but code execution never returns to the awaiting method.

JonnyBee replied on Tuesday, June 26, 2012

Frode,

Your data access is async and does not use Task (not supported yet). So Your DataPortal_Fetch should look like this:

 public void DataPortal_Fetch(object criteria, LocalProxy<BusinessObject>.CompletedHandler callback)
{
  try
  {
  Text = "Hello world";
 callback.Invoke(this, null);
  }
  catch (Exception ex)
  {
 callback.Invoke(this, ex);
  }
}

Since Your data Access code is going to call asyncronous webservices you must Accept a callback and is responsible to Call this to notify calling code that async operation is Complete.

This is probably going to change, see 3) in Rockys previous post but for the time beeing the callback parameter is required.

RockfordLhotka replied on Tuesday, June 26, 2012

By the way, you can absolutely use async/await in the current implementation.

public async void DataPortal_Fetch(..., callback)
{
  try
  {
    await MyAsyncMethodOrOperation();
    callback(this, null);
  }
  catch (Exception ex)
  {
    callback(null, ex);
  }
}

The reason this works is that the data portal won't proceed until the callback is invoked (as you noticed). And the await keyword will block execution at that point in the method until the async operation is complete, so the callback won't be invoked until either an exception occurs, or the async operation completes.

Nilzor replied on Wednesday, June 27, 2012

Your solution works with the DataPortal_XYZ-pattern, Jonny, but when I went back to a ObjectFactory a new problem came up, I'm afraid. The signature of the Fetch-method in the factory class is as follows:

public BusinessObject Fetch(object criteria, LocalProxy<BusinessObject>.CompletedHandler callback)

At runtime I then get this weird ClassCastException:

(A)CompletedHandler[Csla45.WinRt.AsyncAwait.BusinessObject] cannot be cast to (
(B)CompletedHandler[Csla45.WinRt.AsyncAwait.BusinessObject]

Type A originates from 'Csla, Version=4.5.1.0, Culture=neutral, PublicKeyToken=93be5fdc093e4c30' in the context 'LoadNeither' at location 'D:\\coding\\source\\samples\\Csla45.WinRt.AsyncAwait\\Csla45.WinRt.AsyncAwait\\bin\\Debug\\AppX\\Csla.DLL'. 

Type B originates from 'Csla, Version=4.5.1.0, Culture=neutral, PublicKeyToken=93be5fdc093e4c30' in the context 'LoadNeither' at location 'D:\\coding\\source\\samples\\Csla45.WinRt.AsyncAwait\\Csla45.WinRt.AsyncAwait\\bin\\Debug\\AppX\\Csla.DLL'."}

As you can see, the exception basically says class A and B are identical, but still casting fails. This stack overflow-thread had some kind of explanation for this phenomenon, but the case in the question was a bit different. Can you make anything out of this?

 

 

 

 

 

 

JonnyBee replied on Wednesday, June 27, 2012

The callback handler is specified in each Proxy type so for ObjectFactory the method should be like this:

  public class BusinessObjectFactory : ObjectFactory
  {
    public void Fetch(object criteria, FactoryProxy<BusinessObject>.CompletedHandler callback)
    {
      try
      {
        var bo = new BusinessObject();
        LoadProperty(bo, BusinessObject.TextProperty, "Hello world");
        callback.Invoke(bo, null);
      }
      catch (Exception ex)
      {
        callback.Invoke(null, ex);
      }
    }
  }

Nilzor replied on Wednesday, June 27, 2012

Brilliant, that did it! I think we can officially close this thread now :-) Thank you both for the help.

RockfordLhotka replied on Tuesday, June 26, 2012

Right now the local proxy in Silverlight, WP7, and WinRT all use a callback parameter passed to the DataPortal_XYZ method to know that the DataPortal_XYZ method is complete.

Remember that the client-side data portal components and logical server-side data portal components are different things.

  1. I changed the client-side data portal to support async/await.
  2. I am still trying to decide if I want to change the .NET server-side behavior, because that'd break nearly everyone - and that would be bad.
  3. I am now convinced that I WILL change the logical server-side behavior for Silverlight and WinRT to not require the callback parameter. I can't change WP7, because it doesn't support async/await. When WP8 comes out, I'll make it match WinRT of course.

 

Copyright (c) Marimer LLC