Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 5: Astoria, Add Service Reference and WinForms

Even more update on my Mix09 talk “building business applications with Silverlight 3”.  Now for some brand new content – that just could not have been done before this release. 

This demo will take the Application logic we created in my Mix09 talk and put a REST based web service head on it with ADO.NET Data Services.   

image

This might be useful if an application starts as a simple RIA Application but later you discover that you want to add a more explicit services layer to enable a wide range of clients to access your application.  Luckily all your investment in the server application logic continues to work. 

Just to show off the point, we will then consume that from a WinForms applications.  This extends your reach and headroom for using RIA Services even more! 

The demo requires (all 100% free and always free):

  1. VS2008 SP1 (Which includes Sql Express 2008)
  2. Silverlight 3 RTM
  3. .NET RIA Services July '09 Preview

Also, download the full demo files and check out the running application.

Start with the application where we left off in Part 4…  In the the server project, let’s add a REST head to the DomainService.  This will allow any arbitrary client to access the DomainService and gives us a chance to selectively control what gets exposed. 

image

Then we customize the class that was created for us.

 public class SuperEmployeeService : DataService<SuperEmployeeDomainService>, IServiceProvider
 {
     // This method is called only once to initialize service-wide policies.
     public static void InitializeService(IDataServiceConfiguration config)
     {
         config.SetEntitySetAccessRule("*", EntitySetRights.All);
         config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
     }
  

Notice here i am using the “demo” mode with “*” and “All”..  Here is where you can control what aspects of the Domain are meant to be accessed via any client and which are really part of the Silverlight app.   It is a best practice to list them explicitly. 

Now I simply right click and view in browser..  We get the standard ADO.NET Data Services (Astoria) REST head.  But rather than going directly against my database, I now have a formal way to add application logic. 

image

We can even traverse the data via the standard astoria URL formats.  

Again, notice all the calls are run through your DomainService so the application logic controls the access, shape and content of all the data here. 

https://localhost:52878/SuperEmployeeService.svc/$metadata

image

https://localhost:52878/SuperEmployeeService.svc/SuperEmployee(12)

image

Ok – that is cool… but let’s do something more useful.  How about building an WinForms client from this service.    Notice this would work with WPF, Ajax or even any Java client! 

Add a new WinForms application then add a service reference. 

image

Oh, and Shawn Wildermuth, this Add Service Reference is for you!  We talked about it at Mix and now here it is in the bits!  Enjoy. 

Now we add a little form..

image

And some simple code behind… We set up the proxy to Astoria..

 SuperEmployeeDomainService context; 
 public Form1()
 {
     InitializeComponent();
  
     context = new SuperEmployeeDomainService(
         new Uri("https://localhost:52878/SuperEmployeeService.svc/"));
     context.MergeOption = MergeOption.AppendOnly;
 }

Now we can just load the data…

 private void loadButton_Click(object sender, EventArgs e){
  
     var savedCursor = Cursor.Current;
     Cursor.Current = Cursors.WaitCursor;
     var q = from emp in context.SuperEmployee
             where emp.Issues > 10
             orderby emp.Name
             select emp;
  
  
     dataGridView1.DataSource = q.ToList();
     dataGridView1.CellEndEdit += dataGridView1_CellEndEdit;
     Cursor.Current = savedCursor;
  
 }

 

hit F5, press load and you get your data!  Again, through that same set of application logic. 

 

image

 

Now let’s add some code to update the server when data on the client changes..

 

 void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
 {
     var row = dataGridView1.Rows[e.RowIndex].Cells;
     int empId = Convert.ToInt32(row["EmployeeId"].Value);
  
     var q = from emp in context.SuperEmployee
             where emp.EmployeeID ==empId 
             select emp;
     var employee = q.FirstOrDefault();
  
     employee.Gender = row["Gender"].Value as string;
     employee.Issues = Convert.ToInt32(row["Issues"].Value);
     employee.LastEdit = DateTime.Now;
     employee.Name = row["Name"].Value as string;
     employee.Origin = row["Origin"].Value as string;
     employee.Publishers = row["Publishers"].Value as string;
     employee.Sites = row["Sites"].Value as string;
  
     var savedCursor = Cursor.Current;
     Cursor.Current = Cursors.WaitCursor;
     context.UpdateObject(employee);
     context.SaveChanges();
     Cursor.Current = savedCursor;
 }

Here we just handle the event when the cell is done being edited..  Then we find employee that is object that corresponds to this row and update its values. 

Again, this same pattern would work for any client that works with Astoria today..

Comments

  • Anonymous
    July 15, 2009
    Thats cool Brad - you're making all this coding lark a bit too easy for us developers :) When are you going to do a blog that tells us how to mix RIA, Forms Authentication (using a custom membership provider) and Prism v2 (Modularity)? p.s. thanks for replying to my silverlight forum question (RIA Services as Data Services???)

  • Anonymous
    July 15, 2009
    This post is awesome! Thank you!

  • Anonymous
    July 15, 2009
    "Again, notice all the calls are run through your DomainService so the application logic controls the access, shape and content of all the data here. " I'm not seeing DomainService here ?  I think I missed something Brad ?

  • Anonymous
    July 15, 2009
    Sure, look back up at the declaration of that class that defines the Astoria services: public class SuperEmployeeService : DataService<SuperEmployeeDomainService>, Notice that you see it is of type SuperEmployeeDomainService… this is the place you would ordinarily put your EFModel…  But instead we put our DomainService class where you can filter, aggregate, and compose data however you’d like. Does that help?

  • Anonymous
    July 15, 2009
    I like the  REST style service, also WCF will give a toolkit based on REST. Hope they will release soon.

  • Anonymous
    July 15, 2009
    Hi brad, The article is noce. Can you please tell where you have updated the article for using RIA services ? Thanks, Thani

  • Anonymous
    July 15, 2009
    Brad, In your example you have a specific item template called 'Domain ADO.Net Data Service' as well as a 'ADO.Net Data Service'. I don't have the option of choosing a Domain ADO.Net Service :(

  • Anonymous
    July 15, 2009
    Now with .Net RIA Services, there is yet another option for the middle tier for Silverlight.  What are your thoughts on when to use .Net RIA Services vs WCF (Basic HTTP Binding/Binary Binding) vs ADO.Net Data Services for Silverlight & WPF Apps.

  • Anonymous
    July 15, 2009
    Forget my last comment - found it DOH

  • Anonymous
    July 16, 2009
    As with Scott, I didn't realize the new project type  :) Very cool - thanks Brad

  • Anonymous
    July 16, 2009
    Kiran - Think of RIA Services as just a layer on top of WCFAstoria.... So eventually all the goodness of WCF will just shine right through..   As far as when to use what, I'd use WCFAstoria directly when you are building a service and use the RIA Services layer on top when you are building a Silverlight application. Does that help?

  • Anonymous
    July 16, 2009
    I hope you can render this app in vb, it's not so useful to approx half of us in c#. Also, I am not able to run the downloaded solution. It fails on the db. I have sql server 2005 express and sql server 2008 std installed. I think it expects sql server 2008 express. I've not been able to find a way around this yet.

  • Anonymous
    July 16, 2009
    What are the Deployment requirements for .NET RIA. Will all browsers be supported. Are there any client side installs or requirements??(Like IE7.0 or higher)? please advice. thank you

  • Anonymous
    July 16, 2009
    I'm with Bell...I cannot get the example running and have the same db issue and installs of sql server...

  • Anonymous
    July 16, 2009
    The documentation for RIA Services says: "- Every public property on the server’s entity class name will be exposed by the entity proxy class " and has a footnote clarifying: "Except for properties whose type would not be available on the Silverlight client, such as DAL-specific types" I have a DAL layer that has plenty of DAL-specific types (Dictionaries mostly), but I still get a compiler error (I assume during the RIA code generation process) of: "C:Program FilesMSBuildMicrosoftSilverlightv3.0Microsoft.Ria.Client.targets(99,6): error : Entity 'CL.DAL.EntityClasses.UserEntity' has a property 'CustomPropertiesOfType' with an unsupported type." The Property definition is as follows: public override Dictionary<string, string> CustomPropertiesOfType { get { return UserEntity.CustomProperties;} } How can I avoid this error?  Astoria allows for an [IgnoreProperties] attribute.  Is there something similar for RIA? Thank you!

  • Anonymous
    July 16, 2009
    >> What are the Deployment requirements for .NET RIA. Will all browsers be supported. Are there any client side installs or requirements??(Like IE7.0 or higher)? On the client all you need is Silverlight 3... that works with IE, FireFox, Chrome, and Safri... it works on Mac and Windows and with Mono it also works on Linux!

  • Anonymous
    July 16, 2009
    re the db issue - from what I've read some of us have issues because the mdf file based nw that comes with the download expects to be launched by sql server 2008 express. There may not be an easy workaround for this issue but it'd be cool to hear of one. Alternatively, could provide some guidance re switching the db refs to a nw db that's running on sql server 2008 std? I have not tried any such workaround. I'm not sure that the EF config would survive the change...what approach would help the demo app surface in operational order? Demo apps like you've created here are very very helpful for those of us that are trying to get a handle on all the new stuff coming out. A vb version would also be appreciated.

  • Anonymous
    July 16, 2009
    The comment has been removed

  • Anonymous
    July 16, 2009
    Brad, In what circumstances should be use ADO .net services over WCF services?

  • Anonymous
    July 17, 2009
    ADO.NET Data Services is best when you exposing large chucks of data fairly directly... WCF is better if you are more operational and it is not simply CRUD...  Does that help? Also, WCF supports things like duplex and Binary formats, so if those are required, then you should use WCF..    I have examples of doing both in comming blog posts..  

  • Anonymous
    July 17, 2009
    Maybe the no-db posts will work out ok. But frankly I never like demos that do not rely on an actual db for crud ops (xml file of something like that). Couldn't you just have the demo point to an installed copy of northwind? IE not a file that gets pulled in to the project? I don't think anything you're doing is sql server 2008 dependant, per se.

  • Anonymous
    July 19, 2009
    > Couldn't you just have the demo point to an > >installed copy of northwind? IE not a file that gets >pulled in to the project? I don't think anything >you're doing is sql server 2008 dependant, per se. Sure -- if you just take the northwind.mdb file from the App_Data and host it in a SQL Server and change the connection string you should be good to go..  

  • Anonymous
    July 21, 2009
    ok, I'm missing something obvious. I have the latest updates to everything, using VS2008. I have created an EntityModel and the Domain service: public class KerdaService : LinqToEntitiesDomainService<KerdaEntities>. Following the above instructions I created a web service: public class WebDataService : DataService<KerdaService>, IServiceProvider. and updated the InitializeService:            config.SetEntitySetAccessRule("", EntitySetRights.AllRead);            config.SetServiceOperationAccessRule("", ServiceOperationRights.All); When I run the service i get this:

  • <workspace>  <atom:title>Default</atom:title>  </workspace> Nothing seems to be available? Looking at the $metadata produces nothing as well. What am i missing? I've gone over the sample application and can't seem to find anything out of place. Is it a web.config setting? Property on the project. Any help would be appreciated. thanks
  • Anonymous
    July 21, 2009
    What does your KerdaService look like?  Did you add a query method?  

  • Anonymous
    July 21, 2009
    There are 16 Entities in the model. The KerdaService was generated with all 16 Entities. Each Entity has the standard Get,Insert,Update, Delete in the Service:      public IQueryable<Vendor> GetVendor()      {         return this.Context.Vendor            .Include("CountryISO3166_1")            ;      }      public void InsertVendor(Vendor vendor)       {         this.Context.AddToVendor(vendor);      }      public void UpdateVendor(Vendor currentVendor)  {         this.Context.AttachAsModified(currentVendor,                      this.ChangeSet.GetOriginal(currentVendor));      }      public void DeleteVendor(Vendor vendor) {         if ((vendor.EntityState == EntityState.Detached)) {            this.Context.Attach(vendor);         }         this.Context.DeleteObject(vendor);      } I have done as little as possible to get this to work. All the code is pretty much the same as when RIA generated it. I have generated the Metadata as well and attached Annotations, Include, Required and so on. Do I need to annotate the methods in the service ? Your example has no annotations in the service though, so I'm just lost. thanks

  • Anonymous
    July 21, 2009
    Sorry, one more thing. The Silverlight Application, what liittle i have done,  is able to connect to the data.

  • Anonymous
    July 21, 2009
    ogreboy -  that is odd...do you want to send me the project and I can debug?  bradA@microsoft.com

  • Anonymous
    July 22, 2009
    thanks for your interest. since I really only have much of a shell I am going to start over and regenerate everything again, Mabey I did something  i shouldn't have. When I get there I will try to insert the WebDataService and see what happens. If my problem continues I will let you know. thanks again

  • Anonymous
    August 01, 2009
    Brad, Why is that when I created a plain Web App using ADO.Net Data Services template and a Domain Service as data source for the Data Service it does not expose any data?

  • Anonymous
    August 02, 2009
    GusG - I think you need to edit the service to say what entities to expose... You can use "*" for all if you'd like..  

  • Anonymous
    August 25, 2009
    Once we have our data showing in the Domain ADO.Net Data service (in the view browser), how do we hook this up to RIA.  I tried adding a Domain Service Class and the Available DataContexts/ObjectContexts only has the empty domain service class to select from.  The Domain ADO Data service does not show up.. I might be missing something but i figured it would show up here.

  • Anonymous
    August 31, 2009
    Just noticed a gotcha when trying to put together this project myself.  Be sure to include the correct version of the System.Data.Services dll from the path "C:Program FilesMicrosoft SDKsRIA Servicesv1.0LibrariesServerSystem.Data.Services.dll".   You need to use the RIA Services version of the DLL or your call to your domain service will return no entities : <service xml:base="http://localhost:56354/MyRest.svc/"> <workspace> <atom:title>Default</atom:title> </workspace> </service>

  • Anonymous
    September 23, 2009
    I'm having a problem implementing this. I have a working DesignDataService : LinqToEntitiesDomainService<DesignRepositoryEntities> that I can hit from my Silverlight application. I'm attempting to add a Domain ADO.NET Data Service class: WebDataService1: DataService<DesignDataService>, IServiceProvider However, inside the call to GetService() when the serviceType parameter is of type {System.Data.Services.Providers.IDataServiceProvider}, I get a MissingManifestResourceException at the call to this.provider.GetService(serviceType): Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "System.Data.Services.Providers.DomainService.resources" was correctly embedded or linked into assembly "System.Data.Services.Providers.DomainService" at compile time, or that all the satellite assemblies required are loadable and fully signed. Any clues? All of my RIA assembly references are marked with "copy local". My web app's "bin" folder does not have any language specific subfolders.