Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 9: POCO and Authentication Provider


I have gotten lots of good comments on my series updating my Mix09 talk “building business applications with Silverlight 3”.  Some customers have asked about the “live” version I have running on one of Scott Haneslman’s servers (thanks Scott!)

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, of course, check out the running application.

Scott gave me a FTP access and a web server, but I didn’t want to hassle with setting up a database (though he did offer).  So I thought I’d use the POCO support in RIA Services to just get data from plain old CLR objects.  Personally, I think far too many of our samples show only Entity Framework… So this is a good excuse to show that off. 

So, back to your application diagram, i want to use this post to focus on POCO as a data source.

image

First, my goal was to make the minimum changes.  I didn’t want to touch the client at all, nor did I want to change any of my business logic.  I just wanted to move the app from EF\SQL to a POCO data source. 

Turns out this was simple enough to do.  First I deleted the northwind.mdf file from App_Data then I deleted the EF model.  

Then I added a SuperEmployee class.. I went ahead and added the metadata directly. 

public class SuperEmployee
{
 
    [Key]
    [ReadOnly(true)]
    public int EmployeeID { get; set; }
 
    public DateTime LastEdit {get;set;}
 
    [Display(Name = "Name")]
    [Required(
        ErrorMessage = "Super hero's require names!!")]
    public string Name { get; set; }
 
    [Display(Name = "Gender")]
    [RegularExpression("^(?:m|M|male|Male|f|F|female|Female)$",
        ErrorMessage = "Even super heros are  M\\F or Male\\Female!")]
    public string Gender { get; set; }

Then I created SuperEmployeeList class that has all the data

List<SuperEmployee> list = new List<SuperEmployee>()
{       
         
        new SuperEmployee() {
        EmployeeID=1,
        Gender="Male",
        Issues=982,
        Name = "Alfred",
        Origin="Human",
        Publishers="DC",
        Sites="first appears in Batman #16"},
                
 
        new SuperEmployee() {
        EmployeeID=2,
        Gender="Male",
        Issues=518,
        Name = "Alfred E. Neuman",
        Origin="Human",
        Publishers="Ec",
        Sites="first appears in MAD #21"},

 

Then I added a couple of simple methods to make encapsulate access.

public IEnumerable<SuperEmployee> GetEmployees()
{
    return list.ToArray();
}
 
public void Add(SuperEmployee emp)
{
    list.Add(emp);
}

Then some small tweaks to my DomainService implementation.  Notice here I derive directly from DomainService directly rather than using the LinqToSqlDomainService or EntityFrameworkDomainService classes.    I think this will be reasonably common..

[EnableClientAccess()]
public class SuperEmployeeDomainService : DomainService
{
    SuperEmployeeList Context = new SuperEmployeeList();
    public IQueryable<SuperEmployee> GetSuperEmployees()
    {
        return Context.GetEmployees().AsQueryable();
    }
 
    public IQueryable<SuperEmployee> GetSuperEmployee(int employeeID)
    {
        return Context.GetEmployees().ToList()
            .Where(emp => emp.EmployeeID == employeeID).AsQueryable();
            
    }
 
    public void InsertSuperEmployee(SuperEmployee superEmployee)
    {
        Context.Add(superEmployee);
    }
public override void Submit(ChangeSet changeSet)
{
    base.Submit(changeSet); 
    //todo: Submit changes to the store.. (for example, save to a file, etc
}

I should also override Submit to save off the changes (say to a file or some sort of backing store).. but for the demo I wanted to keep them static so no one puts in bad data into my site.

Hit F5 and everything else works.. No changes to the Silverlight client or the ASP.NET client (for SEO)..  This same flexibility allows you to move from one data access technology to another without all your clients having to be updated. 

Authentication

As you saw my earlier post, we have a very cool new template that gives you log in and create new user support. 

image

I *had* to enable that in the demo..  At least so folks could play around with it.  By default we use the aspnetdb.mdb and SQLExpress… so this needed to be updated just like the above example. 

Because we simply plug into the ASP.NET Membership system that shipped in ASP.NET 3.0 this is a pretty well explored and documented area.     But here is the brief on it. 

In web.config in the server project, under the system.web section add:

 
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <add name="SimpleMembershipProvider"
             type="MyApp.Web.SimpleMembershipProvider"
             minRequiredPasswordLength="2"
             minRequiredNonalphanumericCharacters="0" />
      </providers>
    </membership>

Then just implement the SimpleMembershipProvider… Here I did a demo-only model that accepts any user id and password. 

public class SimpleMembershipProvider : MembershipProvider
   {
      public override bool ValidateUser(string username, string password)
      {
        return true;
      }
      public class MyUser : MembershipUser
      {
 
      }
      public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
      {
        status = MembershipCreateStatus.Success;
        return new MyUser();
       }

Clearly in a real application you will want to plug into your user management system.  But, again because ASP.NET’s system has been around for so long there is support out there for just about any system.  Also check out a great book on the subject Stefan Schackow’s Professional ASP.NET 2.0 Security, Membership, and Role Management.

Comments (19)

  1. Stefan Olson says:

    Brad,

    Is your site running on Scott’s machine in medium trust or full trust? I understand at the moment that .net RIA services requires full trust, which makes it impossible to use it on a hosting service like Go Daddy, or have I misunderstood that?

    …Stefan

  2. BradA says:

    Stefan — It is full trust right now… I am told the next update will work partial trust..  

  3. Shawn says:

    Our poco/custom repository/etc would have to implement IQueryable for this to be truly useful right?

    Say I do data access in my custom repository…I’d have to implement IQueryable in my repository to be able to filter and query the database with whatever filters I use on the client?

  4. Hi,

    I would like to share my article on Authentication with silverlight .

    http://geekswithblogs.net/thanigai/archive/2009/05/20/silverlight-3-with-ria-authentication-service.aspx

    It uses ASPNetDB.

    Thanks,

    Thani

  5. Brad,

    Is a step-by-step walkthrough available for the Business Apps Example for Silverlight 3 RTM and .NET RIA Services?

    Excellent series of blog updates!

    Best regards, Rob

  6. VeeMat says:

    Brad,

    Thanks a lot for the series. They are great.

    I have a question on real world situation.

    I have Sales Order that is split into 3 entities.

    Sales Order Header, Sales Order Lines and Product.

    Sales Order Header has many lines and each line has a product.

    How to Insert,Update,Delete a Sales Order (All 3 entities related to each other).

    All need to happen in a transaction and with business validations on each entity.

    Any help or direction is greatly appreciated.

    Thanks

    Vee.Mat

  7. Stefan Olson says:

    Brad,

    Do you know if the next update that supports medium trust will work on the .net framework 3.5 SP1. I understand it will probably only work on.net framework 4.

    This is a problem as far as hosted providers go because I doubt that Go Daddy will have the .net framework 4 available on its servers until at least mid next year.

    …Stefan

  8. BradA says:

    This is great feedback Stefan — we talked about this issue today and are actively looking at a solution to make it work in semi-trust on 3.5.. stay tuned!

  9. BradA says:

    VeeMat — this is a great scenario and one that will be more clean in the next drop… There is an Include attribute that you can use to specifiy what other entities to operate on as a unit..  

  10. BradA says:

    > Our poco/custom repository/etc would have to implement IQueryable for this to be truly useful right?

    >Say I do data access in my custom repository…I’d have to implement IQueryable in my repository to be able to filter and query the >database with whatever filters I use on the client?

    That is right, you need to implement IQuerable to get all the cool composition around sorting paging filtering, etc.. But in the WCF example, I show how you can get pretty close by using parameters to your query methods http://blogs.msdn.com/brada/archive/2009/07/17/business-apps-example-for-silverlight-3-rtm-and-net-ria-services-july-update-part-8-wcf-based-data-source.aspx

    ..brad

  11. MichaelD! says:

    Brad,

    This is a great sample.  Thank you for releasing this.

    I’m trying to get your MyApp.WebAdmin site working.  Is this supposed to work out of the gate?  I get the following exception what I try to view it:

    The base class includes the field ‘DynamicDataManager1’, but its type (System.Web.DynamicData.DynamicDataManager) is not compatible with the type of control (System.Web.DynamicData.DynamicDataManager).

    Thank you 🙂

    Michael

  12. BradA says:

    MichaelD! –

    Utz – Nope, that WebAdmin project is not suppose to be there..   It is some testing i did for a future post..  Stay tuned… we will do Dynamic Data soon 😉

  13. swo says:

    Thanks for this great sample.

    I have a similar Question than VeeMat.:  

    I added a property to SuperEmployee class

    public Role MyRole { get; set; }

    where Role is a simple class  

    public sealed class Role

    {

           [Key]

           public string RoleName { get; set; }

           public bool IsIn { get; set; }

    }

    After compiling, I got no MyRole property in the generated Entity.

    When I add the [Include Attribute] i get the compiler error:

    Invalid Include specification for member ‘UserInformation.MyProperty’. Non-projection includes can only be specified on members with the AssociationAttribute applied.

    What can I do? And is it possible to export  a

    public RoleCollection List<Role> as property?

    Thanks

  14. ASchrijver says:

    I have the same problem with this POCO approach.

    If you have a 1 to many relationship, say between Products and Categories, then RIA Services ignores the Categories collection property on the Product domain class in client-side code generation (which is defined as IEnumerable<Category>).

    Adding the IncludeAttribute gives "Invalid Include specification for member ‘Product.Categories’. Non-projection includes can only be specified on members with the AssociationAttribute applied."

    Ideas anyone?

    Thanks.

  15. ASchrijver says:

    I fixed the problem using a workaround.

    In order to use define a System.ComponentModel.DataAnnotations.AssociationAttribute I needed a foreign key property on Category.

    The Product objects, however are retrieved from a WCF service and already have the Categories loaded and Category objects do not have a property ProductId.

    So I created a small wrapper object that wraps Category objects just after Products are retrieved from the service and adds the ProductId to it.

    In Products I now have:

    [Association("Categories", "Id", "ProductId")]

    [Include]

    Public List<Category> Categories

    {

        …

    }

    This works, but the solution is far from ideal.

    However, in the meantime the proxy class seems to solve another issue that I had as well, namely that metadata validation of WCF proxy objects (created with Service Factory Modeling edition) did not work properly with RIA Services (only the RequiredAttribute and KeyAttribute were honoured, the rest was ignored).

    So, that is something good coming with something bad, it seems 😉

  16. ASchrijver says:

    BTW, I didn’t say this yet, but I really appreciate the long list of articles on RIA Services. Thank you, Brad!

  17. necro_mancer says:

    hi there,

    I have a couple of things to add. In order to run Silverlight 3 with RIA Services on a shared server, there are several things that you need to check. The followings must be installed on the server:

    1. .NET3.5 Framework

    2. Full Trust mode must be enabled

    3. Install the Visual Web Developer 2008 tool

    4. Install the Visual Studio 2008 Service Pack 1

    5. Run the Silverlight 3 Toolkit

    6. Run the RIA Service Installation

    7. Silverlight can run on either IIS6 or IIS7

    I am currently hosting my Silverlight 3 (+ RIA Service) with ASPHostCentral (http://www.asphostcentral.com) and so far, everything works smoothly.

  18. Patrick Boyd says:

    How do you set up the POCO data source to handle an object that has an object as a property (we have a set of classes serialized from an XSD).

    For instance, we have a client object with a property of ClientTitle (which has two properties, one int (ID) and one string (Value).  How do i get Dynamic data to show me the string?

  19. Greg Gum says:

    I just called GoDaddy and they confirmed that the shared hosting does not run in full trust and cannot be configured to run in full trust.  

    Am looking forward to that next update!

    Greg