Minggu, 23 Januari 2011

Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 24: Stored Procedures


Still updating my Mix 09 Silverlight 3 + RIA Services talk with more fun stuff. While many of the RIA Services examples we have shown thus far do CRUD directly against database tables, I certainly recognize that many scenarios require using stored procedures in the database to encapsulate all data access.

You can see the full series here.

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

  1. VS2008 SP1
  2. Silverlight 3 RTM
  3. .NET RIA Services July '09 Preview

Check out the live site Also, download the full demo files

In this example, I am going to encapsulate all our data access in stored procedures. I will continue to use Entity Framework to access these stored procs, but you could of course use LinqToSql or ADO.NET directly.

Add Stored Procedures

The first step is to create a set of stored procedures in the database.

In Server Explorer open up the Database, select the Stored Procedures node and “Create New Stored Procedure”

image

These are very, very basic. My goal here is to show you how to get started, you can then add additional logic as needed while following the same basic overall pattern.

Let’s start by adding some query stored procedures:

ALTER PROCEDURE dbo.CoolSuperEmployees



AS



SELECT  SuperEmployees.Name, SuperEmployees.EmployeeID,SuperEmployees.Gender,SuperEmployees.Origin,SuperEmployees.Issues,SuperEmployees.Publishers,SuperEmployees.LastEdit,SuperEmployees.Sites



FROM SuperEmployees 



WHERE SuperEmployees.Issues Between 10 And 99999



 



RETURN




Notice this stored proc does not directly support paging. You could take a paging information if that is required.



and to get a particular employee







ALTER PROCEDURE dbo.GetSuperEmployee



    (



    @EmployeeID int 



    )



AS



    SELECT  SuperEmployees.Name, SuperEmployees.EmployeeID,SuperEmployees.Gender,SuperEmployees.Origin,SuperEmployees.Issues,SuperEmployees.Publishers,SuperEmployees.LastEdit,SuperEmployees.Sites



FROM SuperEmployees 



WHERE SuperEmployees.EmployeeID = @EmployeeID



 



RETURN




Update:







ALTER PROCEDURE dbo.UpdateSuperEmployee



    (



    @EmployeeID int,



    @Name nvarchar(MAX),



    @Gender nvarchar(50),



    @Origin nvarchar(10),



    @Issues int,



    @Publishers nvarchar(10),



    @LastEdit datetime,



    @Sites nvarchar(MAX)



    )



 



AS



Update SuperEmployees



Set



  Name = @Name,



  Gender = @Gender,



  Origin = @Origin,



  Issues = @Issues,



  Publishers = @Publishers,



  LastEdit = @LastEdit,



  Sites = @Sites



Where 



 EmployeeID = @EmployeeID 




Insert:







ALTER PROCEDURE dbo.InsertSuperEmployee



    @Name nvarchar(MAX),



    @Gender nvarchar(50),



    @Origin nvarchar(10),



    @Issues int = 0,



    @Publishers nvarchar(10),



    @LastEdit datetime = null,



    @Sites nvarchar(MAX)



AS



Insert into SuperEmployees



(



 Name,



 Gender,



 Origin,



 Issues,



 Publishers,



 LastEdit,



 Sites



)



Values



(



  @Name,



  @Gender,



  @Origin,



  @Issues,



  @Publishers,



  @LastEdit,



  @Sites



 )



Select SCOPE_IDENTITY() as Id




And finally delete:







ALTER PROCEDURE dbo.DeleteSuperEmployee



    (



    @EmployeeID int 



    )



 



AS



Delete From



   SuperEmployees



   



Where 



   EmployeeID = @EmployeeID






Update the Entity Framework Model



Now let’s create an Entity Framework model that knows how to access the data via these Stored Procs. Let’s start by creating a new Entity Framework Model



image



Then we select the SuperEmployees table and all of the storedprocs we created above



image



Next, I like to set the properties on the SuperEmployee entity to make the naming more clear in the .NET world.



image





Next, we wire up the CUD (create, update, delete) operations for this table to go through the storedprocs we just wrote.



First we setup the Insert function to map to the “InsertSuperEmployees” storedproc



image





Visual Studio automatically sets up the mapping, if you need to tweak this based on your stored procs, you certainly can.



image



Repeat this for Update and Delete, such that they are all mapped.





image





Now we need to do the same thing for the query methods. Open the Model Browser and find the stored proc for “CoolSuperEmployee”. Right click and select “Create Function Import”.



image





Then we set up a mapping to return SuperEmployees



image



And repeat for the GetSuperEmployee (int employeeID)…





Now we have our model all setup, let’s go back to our DomainService and update it to use these settings.







Update the Domain Service



The DomainService allows you to create custom business logic and easily expose this data to the Silverlight client. The good news is this looks almost exactly like the pervious examples.



First, let’s look at the query methods.





   1: [EnableClientAccess()]



   2: public class SuperEmployeeDomainService : 



   3:     LinqToEntitiesDomainService<NORTHWNDEntities>



   4: {       



   5:     public IList<SuperEmployee> GetSuperEmployees()



   6:     {



   7:         var q = Context.CoolSuperEmployees();



   8:         return q.ToList();



   9:     }



  10:  



  11:     public SuperEmployee GetSuperEmployee(int employeeID)



  12:     {



  13:         return Context.GetSuperEmployee(employeeID).FirstOrDefault();



  14:         



  15:     }




Notice in line 5, we return an IList rather than an IQueryable.. this means that query composition from the client composes at the stored proc level, rather than all the way into the database. This is goodness because we funnel all requests through that stored proc, but it has the costs of maybe returning more data to the mid-tier than the client really needs. You can of course add paging to the stored proc or you can do direct table access for read only scenarios, but still use stored procs for CUD.



Then we have Insert and Update..





   1: public void InsertSuperEmployee(SuperEmployee superEmployee)



   2: {



   3:    Context.AddToSuperEmployees(superEmployee);



   4: }



   5:  



   6: public void UpdateSuperEmployee(SuperEmployee currentSuperEmployee)



   7: {



   8:     this.Context.AttachAsModified(currentSuperEmployee, this.ChangeSet.GetOriginal(currentSuperEmployee));



   9: }




Notice they look just like our previous example, but now these methods eventually call into our stored procs rather than direct table access.





We run it and it works great! Exactly like pervious examples, but this time all data access is via stored procs.





image





For more information on working with stored procedures with Entity Framework or LinqToSql see:



http://blogs.msdn.com/bags/archive/2009/03/12/entity-framework-modeling-action-stored-procedures.aspx


http://blogs.microsoft.co.il/blogs/bursteg/archive/2007/12/17/ado-net-entity-framework-tools-stored-procedures.aspx


http://msdn.microsoft.com/en-us/library/bb384469.aspx

Silverlight 3 Jumpstart Book

Silverlight 3 Jumpstart

David Yack dropped by my office today and we had a good chat about the direction of Silverlight and RIA Services. David has some great feedback for us from several real apps he has been working on.

image He also dropped off a copy of his book Silverlight 3 Jumpstart. While I haven’t read it in detail yet, I love that the book is small and focused, giving readers just what they need to get started with Silverlight. He includes a teaser on RIA Services as well, I hope to see even more on that in the future. ;-)

Enjoy!

Silverlight 3 Navigation Application: New Themes and Tweaks


Corrina, head UX-designer for Silverlight, just posted some cool new themes for the Silverlight 3 Navigation Application and, better yet, some ideas on how to tweak the ones that are out there to make them match your specific scenario. I really love where this is going… Hopefully we will eventually get to the powerpoint like theme support…

My favorite new one is Candy Store…

Enjoy!

Western European ReMix Tour 2009


I was lucky enough to be asked to go on a brief western European ReMix tour. Our goal with these events is to bring the best of Mix 09 (and some new stuff) closer to where some of the best developers and designers in the world live.

A few of my co-workers are going to be heading out on the tour as well including: Ux expert Arturo Toledo, Adam Kinney of expression fame and architect extraordinaire Simon Guest. So you don’t want to miss this.

Here is as much of my schedule as I know today… If you are in the area, please try to join me!

Monday 28 September(Brussels)

Visual Studio User Group 18:00 – 10 Years of Framework Design Guidelines
Check out the details: http://visug.be/Eventdetails/tabid/95/EventId/16/Default.aspx

Tuesday 29th September (Brussels)

ReMix Brussels: http://www.microsoft.com/belux/remix09/#agenda

11-12: What’s new in SL3

13-14: Building Amazing Business Apps with Silverlight 3 and .NET RIA Services

Arch Forum Brussels: http://www.microsoft.com/belux/msdn/terra_lite/events/2009-09-29_ArchitectForum/ArchitectForum.html

14:50-16:00 Business Apps

REMIX09Wednesday 30th September (Finland)

ReMix Finland: http://www.microsoft.com/finland/remix/

11-12: What’s new in Silverlight 3

13-14: Building Amazing Business Apps with Silverlight 3 and .NET RIA Services

 


Thursday 1st October (Vienna, Austria)



ReMix: Vienna, Austria: http://www.microsoft.com/austria/remix/development.aspx



10:45-11:45: What’s new in SL3



12:45-13:45 Building Amazing Business Apps with Silverlight 3 and .NET RIA Services





Friday 2nd October (Portugal)



ReMix: Portugal http://www.microsoft.com/portugal/remix/index.aspx















Check out the other great worldwide ReMix events… Hopefully one is in your area: http://visitmix.com/worldwide/

Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Comments about Adding…


A couple of people mentioned they are having problems getting adding to work in my example. I think there are two issues that are getting people. See the full series

1. You need to hit submit after you add.. Adding only adds to the local collection, to push it to the database, you need to call submit changes. If you’d like to have Add.. always add it to the database, simply add a call to SubmitChanges(). (line 8). But notice this does do a network operation..

   1: void addNewWindow_Closed(object sender, EventArgs e)



   2: {



   3:     var win = sender as AddNewWindow;



   4:     var context = dds.DomainContext as SuperEmployeeDomainContext;



   5:     if (win.DialogResult == true)



   6:     {



   7:         context.SuperEmployees.Add(win.NewEmployee);



   8:         context.SubmitChanges();



   9:     }



  10: }






2. You need to set Issues to some number greater than 100. Otherwise it will add it to the database, but it gets filtered out when the list is refreshed. Look at this code from the DomainService.. see line 4?





   1: public IQueryable<SuperEmployee> GetSuperEmployees()



   2: {



   3:     return this.Context.SuperEmployeeSet



   4:                .Where(emp=>emp.Issues>100)



   5:                .OrderBy(emp=>emp.EmployeeID);



   6: }




Really, I guess I should hint that to the user by setting a min value for issues in the add dialog. You can do that by changing the range attribute in the SuperEmployeesDomainService.metadata.cs file.





   1: [Range(100, 10000,



   2:     ErrorMessage = "Issues must be between 100 and 1000")]



   3: public Nullable<int> Issues;






Related a common question has been how to write code that get’s called *after* the initial load of data is done. Mostly RIA Services’ programming model avoids you having to deal with it, but sometimes there is no other way. So here is a simple example of how to run some code after a load operation is complete.





   1: var context = dds.DomainContext as SuperEmployeeDomainContext;



   2: originFilterBox.ItemsSource = context.Origins;



   3: context.Load(context.GetOriginsQuery(), (lo) => 



   4: { 



   5:     //just to show you how to load..  



   6:     new ErrorWindow("Loaded.."+lo.Entities.Count()).Show(); 



   7: },null);




Hope this helps! I have updated the demo files



Enjoy!

Silverlight 3 Navigation: Even more on Dynamically Loaded Pages


I got a lot of great feedback on my post Silverlight 3 Navigation: Dynamically Loaded Pages… Now MEF Powered!

Dinesh Chandnani decided to do an update to this sample after looking at the feedback and talking to Nikhil Kothari and Wes Haggard from the MEF dev team. The goals for this update are:

  1. Show even more of a web like user model. With the web, you often see all the links in the navigation, but the actual page only downloads once the user clicked the link.
  2. Lose coupling. I need to be able to be able dynamically add, update even remove pages from my application without taking down the app and without rebuilding it.
  3. Built in authentication. In real business apps, we need to protect our data, so authentication is very important. The web has popularized a very interesting model where you are only asked to authentication when you try to do an operation that needs it. For example, i can browse the netflx catalog any time, but I have to log in the minute I try to add something to my queue.

Download the all the source code

Basic Authentication and User Settings

Let’s do a quick run through of what the app does (with no extensions just yet).

image

As you can see, it is the basic Silverlight Business Application template with Home and About pages that you can navigate to. As well as a log in button. But also notice there is a User Settings page who’s link is red which indicates the user needs to log in to see the contents of the page. So if I log in as a user (Login: guest Password: guest**)

image

I am now logged in and can access the Site Settings page, so it is no longer red.

image

On this page, I can edit user level customization of the app. In this case, the background color of this page. This data is stored on the server is the ASP.NET profile store, so each user can have their own settings that will work on any machine they go to.

image

To bring that point home, let’s go in and create a new user, and give that user a different background color.

Click on login

image

then Register Now

image

I registered “guest3”..

Now, i set the background color to be yellow

image

Then I log out and log in as guest and it is back to red.

image

Oh, and what is even more cool, is if you haven’t noticed yet, if you are not logged in, and you click on a link that requires authentication, you are prompted to log in and then the page is shown to you! Very web like.

image

Loading Extensions

Ok – that is cool and all, but this is a MEF blog post, so we have to talk about application extensibility right? The scenario here is that you are building a composite applications that may have many possible pages. The pages that are there are available maybe very dynamic… it may depend on who the logged in user is, in a multi-tenant environment it may depend on the service level of the client, it may also depend on what has been developed yet. In all those cases, we don’t want to rebuild the app each time there is a new extension, in fact we don’t even want to take the app out of production. We’d like to simply xcopy the AdditionalPages.xap extension into a directory and instantly the right clients have access.

image

Simply hitting refresh on the application makes two new pages show up “products” and “site settings”

image

Clicking on the “products” link causes the AdditionalPages.xap to be downloaded.

image

Once the xap is downloaded the page displays

image

Once the xap is downloaded users can navigate between the pages with no delay.

As an aside, this xap also includes a page that only an admin can access. So if you log in as a user, you still can’t access it.

Not logged in at all, you can’t access user or site wide settings

image

Logged in as a guest, you can access only user settings

image

Logged in as admin, you can access both site and user settings

image

Communicating Between Exceptions

What we have shown so far is loading of isolated pages dynamically.. while that is very cool, what is more interesting is where these pages have to interact together. For example, sharing data between pages. As you might guess, MEF has a model that fits in very nicely here.

If you check out the products page, it actually has access to information about the currently logged on user.

image

It gets this information from the main silverlight application via an import. In products.xaml.cs, we are importing the RiaContext (which includes information about who is logged in).

   1: [Import]



   2: public RiaContextBase RiaContext



   3: {



   4:     get { ... }



   5:     set { ... }



   6: }




and in the Silverlight application, in Services.cs we are exporting the RiaContext which is populated from the server.





   1: public static class Services



   2: {



   3:     [Export]



   4:     public static RiaContextBase RiaContext



   5:     {



   6:         get { ... }



   7:     }



   8: }




When the xap gets downloaded to the client, these exports and imports are resolved. Using this model any pages can share state.





Adding Additional Pages



What is very cool about this model is how easy it is to add additional pages.



1. Add a new SilverlightApplication



image





Remove the test page…



image





Remove MainPage.xaml and App.xaml..



Add References



image



DynamicNavigation - David Poll’s Navigation Extension

System.ComponentModel.Composition – MEF


System.Windows.Controls.Navigation


System.Windows.Ria



and add a project reference to PageMetadata



image







   1: namespace YetMoreAdditionalPages



   2: {



   3:     [PageContent(Name="employees")]



   4:     public partial class EmployeesPage : DynamicPage






Now build, and then copy the YetMorePages.xap over to the extensions directory.



image





Hitting F5, now we have our page dynamically loaded!



image











If you are doing active development, i’d suggest setting the build output directory of the extensions to the extensions directory. This avoids the explicit copy step each time.



image







Summary



In this example we looked at how to build an authentication aware, composite silverlight application… you can download the all the source code ..

HanselMinutes Interview on RIA Services


I had a great opportunity to chat with the famous Scott Hanselman recently on .NET RIA Services. We drilled a lot into the background for RIA Services and what the high level patterns we are addressing with RIA Services.

image

<<The Return of 3-Tier Architecture - RIA Services with Brad Abrams/>

Brad Abrams runs a number of teams at Microsoft, most recently working on "Rich Internet Application Services" (RIA). Scott grills Brad on the rebirth of 3-tier architect, XML, REST and JSON. What's this thing about and is it the best way to write data-centric apps with Silverlight?

Enjoy!