How to open a WCF RIA Services application to other type of clients: the SOAP endpoint (3/5)

BookClubScreen021We’ll see here how to open the application used in the 2 previous articles with a SOAP endpoint that will offer us “classical” WCF calls. We’ll then see how to use this new endpoint from a WPF client that will add and delete items. We’ll do the same operations from a Windows Phone 7 client also. The tricky point to be resolved in both cases will be linked to the authentication cookie to handle. It’s needed to pass-through the forms based authentication in place and to be able to execute actions restricted to authenticated users and/or members of a specific role. You will be able to download the Visual Studio 2010 solution containing the job done during these 3 articles (SL Business App, WPF client & Windows Phone 7 application) at the end of this post. You’ll be able also to view these 3 clients in action thanks to a HTML5 video.

This article is the third one out of 5: 

1 – Review of the initial application
2 – How to expose the service as an OData stream consumed by Excel and from a web application built with WebMatrix 
3 – How to expose the service as a “standard” WCF Service used from a WPF application and a Windows Phone 7 application (this article)
4 – How to expose the service as a JSON stream to be used by a HTML5/jQuery web application 
5 – Step by step procedure to publish this WCF RIA Services application to Windows Azure & SQL Azure

Enabling the SOAP endpoint on a WCF RIA Services DomainService

This will be done of course inside the web.config file. However, the Silverlight 4 tools for Visual Studio 2010 doesn’t install by default the required assemblies needed to enable this endpoint. You need to download & install the WCF RIA Services toolkit for that.

Once the toolkit installed, add a reference to the Microsoft.ServiceModel.DomainServices.Hosting assembly and open the web.config file. Under the OData endpoint, add this new endpoint:

<add name="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, 
Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />

Once done, you’ll be able to enter and test this URL in your browser:

http://nameofyourserver:port/ClientBin/NameOfYourSolution-Web-NameOfYourDomainService.svc

And you can use it also to generate the client proxy thanks to the “Add Service Reference…” action under Visual Studio. For instance, you can add a reference to my service deployed in Azure here:

http://bookclub.cloudapp.net/ClientBin/BookShelf-Web-Services-BookClubService.svc

Using the SOAP endpoint from a WPF client

Let’s see how to call the remote methods exposed in our DomainService from a WPF client using a very light UI (== ugly). The purpose is to concentrate ourselves on the essential part. Still, in order to have something not too ugly, I’ve used the free themes available on codeplex here: http://wpfthemes.codeplex.com/

1 – To simplify also the logic, we’ll do read/write operations on the category entities rather than on the books. As the code source shared with the first article only contains the reading logic inside the DomainService to return the categories, we need to update it. To add support for add, update and delete, use this code inside the BookClubService class:

[RequiresRole("Admin", 
ErrorMessage = "You must be part of the Administrator role to insert, update or delete a category.")] public void InsertCategory(Category category) { if ((category.EntityState != EntityState.Detached)) { this.ObjectContext.ObjectStateManager.ChangeObjectState(category, EntityState.Added); } else { this.ObjectContext.Categories.AddObject(category); } } [RequiresRole("Admin",
ErrorMessage = "You must be part of the Administrator role to insert, update or delete a category.")] public void UpdateCategory(Category category) { this.ObjectContext.Categories.AttachAsModified(category, this.ChangeSet.GetOriginal(category)); } [RequiresRole("Admin",
ErrorMessage = "You must be part of the Administrator role to insert, update or delete a category.")] public void DeleteCategory(Category category) { if ((category.EntityState == EntityState.Detached)) { this.ObjectContext.Categories.Attach(category); } this.ObjectContext.Categories.DeleteObject(category); }

These 3 methods allow us to add, update and delete a category. They can only be called from authenticated users members of the “Admin” group. We then ask to the ASP.NET layer (used by WCF RIA Services) to check the authentication level of the incoming requests.

2 – The next step is to add some references to the 2 services that will be available as SOAP after adding the new endpoint. The first one gives you access to the books & categories entities via the URL I’ve just shared you above. The 2nd one handles the authentication part natively available in each Silverlight Business Application with this code:

[EnableClientAccess]
public class AuthenticationService : AuthenticationBase<User> { }

In my case, it’s available in Azure on this URL: http://bookclub.cloudapp.net/ClientBin/BookShelf-Web-AuthenticationService.svc

Name these 2 references BookClubService and BookClubAuthService.

3 – Once these references added, we will be able to start querying your RIA Services from your WPF client. Add these 3 private members and change the default constructor of the main windows of your WPF application by this:

BookClubAuthService.AuthenticationServiceSoapClient authClient;
BookClubService.BookClubServiceSoapClient bookClubClient;
BookClubAuthService.User currentAuthUser;

public MainWindow()
{
    InitializeComponent();
    ThemeManager.ApplyTheme(this, "ShinyBlue");
    authClient = new BookClubAuthService.AuthenticationServiceSoapClient();
    bookClubClient = new BookClubService.BookClubServiceSoapClient();
}

We’re instantiating the 2 client proxies. If you’d like to return all the available categories and to display them inside a ListBox control, here the code-behind to use:

var categories = bookClubClient.GetCategories();
lstCategories.ItemsSource = categories.RootResults;

And here is the piece of XAML to use:

<ListBox Name="lstCategories">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding CategoryName}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Please note that I’m using the synchronous methods generated for the WPF proxy. Inside a Windows Phone 7 or Silverlight client, the proxy generation will only offer you some asynchronous calls. Finally, this first logic gives us this kind of output:

BookClubScreen016

4 – Fine. Up to now, everything was very simple and we had the same results using the OData endpoint. If we want to go a bit further to update the categories’ entities, we need to be authenticated and member of the “Admin” group. For the authentication part, this is very straightforward. You just have to use the 2nd proxy built on the authentication service which gives us the Login() and Logout() method. Then use the following code:

BookClubAuthService.QueryResultOfUser result = 
authClient.Login(txtUsername.Text, txtPassword.Password, true, ""); if (result.RootResults != null && result.RootResults.Count() > 0) { currentAuthUser = result.RootResults.First(); loginStatus.Content = "Welcome " + currentAuthUser.DisplayName; imgUser.Source = new BitmapImage(new Uri(currentAuthUser.PictureURL)); } else { loginStatus.Content = "Error while logging " + txtUsername.Text; }

We can even retrieve the user’s picture he had inserted with its webcam via the main Silverlight 4 application. You’ll then have this kind of output:

BookClubScreen017

You may think at this stage that the job is over as:

– We were properly authenticated by the BookClubAuthService service
– We should then be able to do some protected calls to the BookClubService ?

This is not the case. Indeed, when you go through the FBA (Forms Based Authentication) mechanism, a special cookie is built and sent back in every requests in the HTTP headers to guarantee that the callers is the user having the appropriate rights. This header is hidden and you don’t have to care about it when you’re building a “Silverlight Business Application”. The tooling and the framework handle it for you.

So, we need to find a way to share this cookie between the authentication service and the books & categories entities services.

Here is a first way to do that:

string sharedCookie;

BookClubAuthService.AuthenticationServiceSoapClient authClient = 
new BookClubAuthService.AuthenticationServiceSoapClient();
using (new OperationContextScope(authClient.InnerChannel)) { authClient.Login("theuser", @"thepassword", true, ""); // Extract the cookie embedded in the received web service response // and stores it locally HttpResponseMessageProperty response = (HttpResponseMessageProperty) OperationContext.Current.IncomingMessageProperties[ HttpResponseMessageProperty.Name]; sharedCookie = response.Headers["Set-Cookie"]; } BookClubServiceSoapClient client = new BookClubServiceSoapClient(); QueryResultOfCategory result; using (new OperationContextScope(client.InnerChannel)) { // Embeds the extracted cookie in the next web service request // Note that we manually have to create the request object since // since it doesn't exist yet at this stage HttpRequestMessageProperty request = new HttpRequestMessageProperty(); request.Headers["Cookie"] = sharedCookie; OperationContext.Current.OutgoingMessageProperties[ HttpRequestMessageProperty.Name] = request; result = client.GetCategories(); }

This sample code shows you how to do an “authenticated” calls to the GetCategories() method. This means that if you’ve set some restrictions by attribute like the RequiresAuthentication on the GetCategories() method on the WCF RIA Services part, you’ll be able to goes through thanks to this approach. However, this forces us to use an important amount of additional code to transfer the cookie during each methods call!

To avoid that, we have to find a way to automatically extract the cookie and re-inject it between incoming and outgoing HTTP requests whatever the remote WCF service is called. For that, you can use the “messages inspector” approach of WCF. This one lives between the end of the tunnel and our user code. It can then analyze the stream before sending it on the network and it can also have a look to the answer back from the network before giving it back to the client. The idea is then to build something similar than this diagram:

InspectorVisio

I’m then highly recommending you reading the excellent Enricon Campidoglio’s article: Managing shared cookies in WCF. I’ve simply implemented his solution. Here are the steps to use it.

First, you need to copy these 3 files from his solution: CookieManagerBehaviorExtension.cs, CookieManagerEndpointBehavior.cs and CookieManagerMessageInspector.cs into your WPF project and potentially then change the namespace used in those files by your own. These files contain the code that will inspect every incoming/outgoing message to track any authentication cookie to extract it and re-inject if for you if needed.

To use it, go to the app.config file and under this tag:

<system.serviceModel>

Add those one:

<behaviors>
  <endpointBehaviors>
    <behavior name="EnableCookieManager">
      <cookieManager />
    </behavior>
  </endpointBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add name="cookieManager" type="WpfBookShelf.CookieManagerBehaviorExtension, WpfBookShelf, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
" /> </behaviorExtensions> </extensions>

Then, you need to say to the 2 endpoints that they have to use this endpoint’s behavior:

behaviorConfiguration="EnableCookieManager"

Which should normally give you this kind of XML file:

<endpoint address="http://bookclub.cloudapp.net/Services/BookShelf-Web-AuthenticationService.svc/Soap"
    behaviorConfiguration="EnableCookieManager"
    binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_AuthenticationServiceSoap"
    contract="BookClubAuthService.AuthenticationServiceSoap" name="BasicHttpBinding_AuthenticationServiceSoap" />
<endpoint address="http://bookclub.cloudapp.net/Services/BookShelf-Web-Services-BookClubService.svc/Soap"
    behaviorConfiguration="EnableCookieManager"
    binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_BookClubServiceSoap"
    contract="BookClubService.BookClubServiceSoap" name="BasicHttpBinding_BookClubServiceSoap" />

Once done, we’ll see that the code is much more readable and nice to review! For instance, here is a sample code that will logon the user, generate an add operation followed by a delete operation terminated by a logout:

//Using the first proxy to log in
BookClubAuthService.AuthenticationServiceSoapClient authClient = new BookClubAuthService.AuthenticationServiceSoapClient();
authClient.Login("adminuser", "password", true, "");

//Using the second proxy to manipulate the data
//exposed by RIA Services. The cookie retrieved by the first call
//to the Login() method will be reinjected for you by the WCF Message Inspector
BookClubServiceSoapClient client = new BookClubServiceSoapClient();
QueryResultOfCategory result;

ChangeSetEntry[] returnChangeSet;
ChangeSetEntry[] newItems = new ChangeSetEntry[1];
newItems[0] = new ChangeSetEntry();

//Adding a new category
Category newCategory = new Category();
newCategory.CategoryName = newCategoryName;
newItems[0].OriginalEntity = null;
newItems[0].Entity = newCategory;
newItems[0].Operation = DomainOperation.Insert;
returnChangeSet = client.SubmitChanges(newItems);

//Reloading the Category Set
result = client.GetCategories();

//Retrieving the just added category
var cToDelete = (from c in result.RootResults
            where c.CategoryName.Equals(newCategoryName)
            select c).FirstOrDefault();

//Deleting the just added category
newItems[0].OriginalEntity = cToDelete;
newItems[0].Entity = cToDelete;
newItems[0].Operation = DomainOperation.Delete;
returnChangeSet = client.SubmitChanges(newItems);

authClient.Logout();

Nice, isn’t it? In the little WPF sample client you’ll find in the source code to download, you’ll have this result. If I’m trying to update something without being authenticated or if I’m authenticated with a non-admin account:

BookClubScreen018

The RIA Services layer has then properly done its job by checking if the user was properly authenticated and by checking if it was member of the “Admin” role before trying to let the add operation be executed. Once properly logged, I can now add a new category from my WPF client:

BookClubScreen019

Once inserted, it’s of course immediately available in the main Silverlight application:

BookClubScreen020

Well, you now know everything to be able to write your own WPF client on top of WCF RIA Services. Let’s now review the job to do on the Windows Phone 7 client.

Using the SOAP endpoint from a Windows Phone 7 client

Connecting to the WCF services exposed by RIA Services from Windows Phone will be very similar to what we’ve done with WPF. Still, there are 2 little differences due to the Silverlight nature of Windows Phone:

1 – The WCF client layer of Windows Phone is less rich than the complete version available with the full .NET Framework. For instance, we don’t have the “message inspectors” support on Windows Phone. We will then have to find another way to handle the authentication cookie.
2 – Every WCF calls are asynchronous in Silverlight and thus, under Windows Phone 7.

For the first point, this is hopefully very easy to handle under Windows Phone 7 thanks to the CookieContainer. To use it, you need to add inside the 2 bindings declared in the WCF XML configuration file this property:

enableHttpCookieContainer="true"

You’ll then have this kind of file:

<binding name="BasicHttpBinding_AuthenticationServiceSoap" maxBufferSize="2147483647"
    enableHttpCookieContainer="true"
          maxReceivedMessageSize="2147483647">
    <security mode="None" />
</binding>
<binding name="BasicHttpBinding_BookClubServiceSoap" maxBufferSize="2147483647"
    enableHttpCookieContainer="true"
          maxReceivedMessageSize="2147483647">
    <security mode="None" />
</binding>

Once done, this code should then work:

CookieContainer cookieContainer = null;

private void btnLogin_Click(object sender, RoutedEventArgs e)
{
    authClient = new BookClubAuthService.AuthenticationServiceSoapClient();

    authClient.LoginCompleted += 
new EventHandler<BookClubAuthService.LoginCompletedEventArgs>(authClient_LoginCompleted); status.Text = "Logging " + username + "..."; authClient.LoginAsync(username, password, true, ""); } void authClient_LoginCompleted(object sender, BookClubAuthService.LoginCompletedEventArgs e) { if (!e.Cancelled) { if (e.Error == null) { if (e.Result.RootResults != null && e.Result.RootResults.Count() > 0) { BookClubAuthService.User user = e.Result.RootResults.First(); status.Text = user.DisplayName + " logged."; cookieContainer = authClient.CookieContainer; client = new BookClubService.BookClubServiceSoapClient { CookieContainer = cookieContainer }; client.GetCategoriesCompleted +=
new EventHandler<BookClubService.GetCategoriesCompletedEventArgs>(client_GetCategoriesCompleted); client.GetCategoriesAsync(); } else { status.Text = "Failed logging " + username + "."; } } } } void client_GetCategoriesCompleted(object sender, BookClubService.GetCategoriesCompletedEventArgs e) { if (e.Result != null) { ObservableCollection<Category> list = e.Result.RootResults; listBox1.ItemsSource = list; } }

This code is creating the following sequence:

1 – When the user clicks on the login button, we’re instantiating the WCF client proxy to the authentication service of RIA Services. We’re then subscribing to LoginCompleted event which will notify us if the authentication succeed or not. Finally, we’re launching the login process in an asynchronous manner via the call to the LoginAsync method.

2 – We will be call-backed inside the authClient_LoginCompleted method where we first check if everything worked as expected. If so, we’re saving the authentication cookie returned by the ASP.NET layer and available inside the CookieContainer object. We’re then using this special object inside the 2nd WCF client proxy that will allow us to do authenticated queries to the methods handling our books & categories.

The add, update & delete operations are done in the same way we’ve seen with the WPF client except that every operation are done asynchronously. For instance, here is my code that deletes a category and then checks what happened in the callback method called once the changes has been submitted:

public void DeleteCategory(string categoryNameToDelete)
{
    try
    {
        ObservableCollection<ChangeSetEntry> deletedItems = new ObservableCollection<ChangeSetEntry>();
        ChangeSetEntry newChangeSetEntry = new ChangeSetEntry();

        Category categoryToDelete = (from c in _categories
                                        where c.CategoryName.Equals(categoryNameToDelete)
                                        select c).FirstOrDefault();

        if (categoryToDelete != null)
        {
            newChangeSetEntry.OriginalEntity = categoryToDelete;
            newChangeSetEntry.Entity = categoryToDelete;
            newChangeSetEntry.Operation = DomainOperation.Delete;

            deletedItems.Add(newChangeSetEntry);
            bookClubClient.SubmitChangesAsync(deletedItems);
        }
        else
        {
            MessageBox.Show("Category not found.");
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
void bookClubClient_SubmitChangesCompleted(object sender, SubmitChangesCompletedEventArgs e)
{
    if (e.Error == null)
    {
        ObservableCollection<ChangeSetEntry> returnChangeSet = e.Result;
        var operation = returnChangeSet.FirstOrDefault().Operation;
        if (operation.Equals(DomainOperation.Insert))
            MessageBox.Show("Category added successfully.");
        if (operation.Equals(DomainOperation.Delete))
            MessageBox.Show("Category deleted successfully.");

        LoadCategoriesData();
    }
    else
    {
        MessageBox.Show(e.Error.Message);
    }
}

Thanks to that, you can then quickly create this kind of application (source code available as download at the end of this article) using the template “Windows Phone Pivot Application” as a based.

Displaying all the categories and all the books available in my SQL DB:

BookClubScreen022BookClubScreen023

Trying to insert or delete a category without being first authenticated properly:

BookClubScreen024

Login screen displaying the user’s picture generated from the Webcam with the Silverlight 4 application. We then can add/delete items successfully:

BookClubScreen025BookClubScreen026

You can watch the final result of this article in the video below. I show you how to create a new user using the Silverlight 4 application, how to promote him inside the “Admin” group and how to re-use its identity inside the WPF & the Windows Phone 7 applications to be able to add/delete data exposed by WCF RIA Services and its SOAP endpoints:

Get Microsoft Silverlight


Note:
this h264 HTML5 video will be displayed natively by IE9 & Chrome. There is a fallback done using a Silverlight player on other browsers like IE8 for instance.
 

Here is the source code of the Visual Studio 2010 solution hosting all the projects demonstrated up to now:

Conclusion

We’ve seen during these 3 first articles how to put in place a solution frequently needed by my customers. Silverlight 4 used in conjunction with the WCF RIA Services framework relaying on ASP.NET will offer the best productivity to the developers’ team in charge of writing the Web RIA application that will expose the business data.

Adding an OData endpoint will allow non-developers persons to read the data from the PowerPivot Excel Add-in or will be used in relatively simple web application written with WebMatrix using the OData helper.

At last, the SOAP endpoint will allow clients like WPF, Windows Phone 7, Java or others to modify the data by using the “classical” WCF layer of RIA Services. The productivity of the developers that will go through this layer will be inferior to the experience provided by SL4/RIA Services. For instance, you can’t build LINQ queries on the client side to add filtering/sorting logic that can then go over the network to the server’s data access layer. But to try workaround that, you can think of adding additional methods to the DomainService. For instance, if you’d like to return all the books only members of a specific category like the main Silverlight application is able to do via its DomainDataSource, here is the kind of method you should add to the DomainService for the WPF/WP7 clients:

public IQueryable<Book> GetBooksByCategoryId(int categoryId)
{
    return this.ObjectContext.Books
        .Where(b => b.CategoryID.Equals(categoryId))
        .OrderBy(b => b.Title);
}

The WCF client proxy generation will then expose a new GetBooksByCategoryId() method that will offer you part of the logic available in the richer Silverlight 4/RIA Services experience.

You should now be armed to face a lot of different scenarios where WCF RIA Services will definitely be a good friend. Clignement d'œil

See you soon in the next article dedicated to the JSON endpoint accessed from an HTML5 application.

David

25 thoughts on “How to open a WCF RIA Services application to other type of clients: the SOAP endpoint (3/5)

  1. Hi David,

    On my question about reusing an existing ria service you redirected me on this post.

    Initialy I tried this method to since there was a sample on it on codeplex. But the one thing I was struggling with were associated properties (navigation properties)

    The associations that I see on the server side on the edmx file are not generated on the client side.

    Should I make the association in the metadata of the domainservice on the server side by using of the key, include and association attributes?

    Or how else can I get my related properties generated on the client side?

    Offcourse the related properties on the edmx file are decorated with the soapignore attribute and this can be causing it to.

    Any ideas?

    By the way, if you have a solution you should make a blogpost about it since I can not find anything about this kind of question on the web.

    And then your great posts will be even more complete and a very good reference for other developers with these kind of questions.

    Thx again

    Stijn

  2. Hi Ben,

    Have you download my solution? Does it work well when you're launching my solution on your machine? Which kind of authentication are you using in your project? FBA ou Windows Integrated?

    Regards,

    David

  3. Hi David, i learned a lot thanks to this tutorial and previously with "0 line code" too (I'm french and it was  real pleasure for once !)

    I'm very interresting to use WPF + WCF but i have got some troubles with BookShelf.

    I have Visual Web Developer 2010 express, so the WPF project is not supported. Therefore, I installed C# 2010 express to host my WPF project.

    Due to this configuration, I hosted my web project from IIS to get the service started. I added a crossdomain.xml file at the root of my project for security with grant access.

    After adding a user to aspnet db, I tried to login from the wpf interface. I obtained this error (translated in english) :

    {System.ServiceModel.FaultException`1[WpfBookShelf.BookClubAuthService.DomainServiceFault] : There was a failure using the default 'MembershipProvider'. Please make sure it is configured correctly. Failed to generate a user instance of SQL Server due to failure in retrieving the user's local application data path. Please make sure the user has a local user profile on the computer. The connection will be closed. Inner exception message:  Failed to generate a user instance of SQL Server due to failure in retrieving the user's local application data path. Please make sure the user has a local user profile on the computer. The connection will be closed. (Error detail is WpfBookShelf.BookClubAuthService.DomainServiceFault).}

    When I try to get categories, i get this error (translated in english) :

    {System.ServiceModel.ActionNotSupportedException: The message with Action 'tempuri.org/…/GetCategories& cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).

    Have you got an idea ? Can you help a poor frenchy boy please ?

  4. Hi David,

    Can you explain how associations/compositions are intended to work through the SOAP endpoint?

    When I try to submit a changeset with 2 entries, one of a parent entity and one of a child, i get "child cannot be updated independently from its parent".

    I assume I have to do something with the Associations collection .. but documentation on that property is shady, and a KVP<string,int[]> leaves more questions than answers.

    TIA

  5. This great article clearly shows how WCFRIA authentication works, but I have another interesting thing.

    When I try to add another WCF service to the same web solution and add service reference in the silverlight project, I found that the cookie is auto sent with the WCF call! I could use httpcontext to get the user identity in WCF service. It seems that WCFRIA component auto add cookie to any WCF service in the same Silverlight project, I wonder how did it happen. Is there something like "global message inspector" ?

  6. Dear David.

    This is an awesome article but i got some problem when implement WCF RIA like this .

    I build Silverlight & WPF with same Domain Service ,everything is ok but when on Silverlight Client ,although i insert-update-delete a record but on WPF Client nothing happen immediately ,i have to re-run WPF Client to see the change.

    So what should i do to resolve this problem?

    Sorry for my poor english :).

    Thanks & regarding.

  7. @Snowdreamist: no, I rather think that this is the browser which send back the auth cookie to your webserver. Even if you add another WCF service, I guess it still hosted in the same server/domain as your WCF RIA Services logic. That's why, for the SL application and thus the browser, it's sending back the cookie.

    @Kenny: that's normal. There is no push mechanism in RIA Services. If you want the data to be automatically updated in the WPF client, you need to do some polling to check for new data.

    David

  8. Dear David.

    Thanks for your advice.

    But i got another problem :

    I had a domain services (build in Silverlight Business Application Web) the Silverlight App local (e.g TestAppSilverlight and TestAppSilverlight.Web) is ok which i can implement CRUD method. (but i can't async this app !!!)

    But when i deploy this domain services via SOAP-ODATA-JSON for another Silverlight App ,i got big problem when implement this service (with SOAP-VS 2010 debug some error inside the sevice,with ODATA-JSON are ok) and when i retrieve some record (via ODTA-JSON) i got message from IE like that :

    ===========

    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) Timestamp: Wed, 20 Apr 2011 03:27:25 UTC

    Message: Unhandled Error in Silverlight Application Silverlight does not enable you to directly enumerate over a data service query. This is because enumeration automatically sends a synchronous request to the data service. Because Silverlight only supports asynchronous operations, you must instead call the BeginExecute and EndExecute methods to obtain a query result that supports enumeration. at System.Data.Services.Client.DataServiceQuery1.System.Collections.Generic.IEnumerable<TElement>.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at SilverlightClient.MainPage..ctor() at SilverlightClient.App.Application_Startup(Object sender, StartupEventArgs e) at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args) at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName) Line: 1 Char: 1 Code: 0

    ================

    What should i do now 🙁 ?

    Plz help me.

  9. Hi,

    great article I was able to easily put soap onto my services and the use them in both a WPF client and a monotouch client for the iphone with authentication. My question is this, is there a way to exclude certain methods on the SOAP service that is in the RIA service?

    For example, i have a user registration service that I do not want to be accessible via soap.

    many thanks,

    Jeza

  10. Hi jeza,

    Thanks for your feedback. No, I can't see a way to prevent some methods to be available in the SOAP endpoints while available in the based SL endpoint. The only way is maybe to create a separate DomainService containing the logic to be available only for the SL client and vice versa.

    Bye,

    David

  11. Thanks for the detailed article.  I just came here to verify if I had everything right for my RIA Services SOAP endpoint.

    –Raghav

  12. Hi, David

    I have a problem with adding service reference to authentication domain service. I created Silverlight Business Application, there is AuthenticationService.cs in folder "Services" (.Web project), in web.config added:

    <domainServices>

         <endpoints>

           <add name="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

           <add name="Json" type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

           <add name="OData" type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

         </endpoints>

       </domainServices>

    Then I added wpf application project to this solution, add now try to add service reference but cannot find (http://localhost:52878/TestApp-Web-AuthenticationService.svc/soap or http://localhost:52878/TestApp-Web-Services-AuthenticationService.svc/soap don't work)

    Could you please advice me what to do?

  13. Hi David

    I have a problem with adding service reference to authentication domain service. I created a Silverlight Business Application in VS2010, there is a AuthenticationService.cs in folder Services (.Web project). In web.config added endpoints:

    <system.serviceModel>

       <domainServices>

         <endpoints>

           <add name="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

           <add name="Json" type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

           <add name="OData" type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

         </endpoints>

       </domainServices>

       <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

     </system.serviceModel>

    and reference to Microsoft.ServiceModel.DomainServices.Hosting.dll

    Then I added wpf application project to solution and try to add service reference (http://localhost:52878/TestApp-Web-AuthenticationService.svc/soap and http://localhost:52878/TestApp-Web-Services-AuthenticationService.svc/soap) without result.

    Could you help me?

  14. Anyone have David's source code for this series. Can you give me a link?

    Thanks again for this series

Leave a Reply

Your email address will not be published. Required fields are marked *