Wednesday 22 August 2012

Entity Framework - Attach Detach Object Graph

Entity Framework and RIA Services do not allow Entities to be added/removed from cross containers. In order to move Entity from one DomainContext/ObjectContext to another DomainContext/ObjectContext, we need to recursively detach the object graph and attach it to other DomainContext/ObjectContext.Or else we might encounter the following exception -
"cannot be attached to this EntityContainer because it is already attached to another EntityContainer"


So what is going wrong here - School is member of 'ctx' Context and without Detaching it from 'ctx' we are trying at Attach into 'tempctx'. Note every instance of Context has a unique EntityContainer.

Now, solution of this problem is every simple. Before attaching school into 'tempContext' call a Detach on 'ctx' like below - 


Also,  When we try to detach entity from old 'ctx' and attach it to 'tempctx', it may give you an error that "entity with same identity already exists in the EntitySet" and it will throw an exception. In this case we will just simply reuse the existing entity instead of attaching the entity we have.
 
Object Graph
 
Single entity can be easily detached and attached from EntitySet where it belongs, but the problem comes when navigation properties of entity are not empty. Entity object along with navigation properties is called Object Graph because if you notice, navigation property’s navigation property will contain reference to same entity and that will result in endless recursive code for Detach/Attach. Now we will look at the solution to deal Atttach/Detach with the EntityGraph-

Look at the following Detach method, which I have created as a Extension Method  -

And Following is as Attach method -

Now see the difference with the traditional approach i.e 'Method1' it showing the same expected error -

However if take the advantage of the above created Extension method we don't get any such error and the result to as below -

 In my Next Post - I ll address the Partial Submit Changes where l am using the same 'tempctx' to apply SubmitChanges instead of SubmitChanges from the main 'ctx'.

Friday 17 August 2012

6. Silverlight and WCF RIA Services –Authentication

It’s a fairly common requirement that a business service authenticates a client and it’s usually (at least) for the purpose of authorisation whereby we can control which users have access to an application or to some of its functionality.

The two ways you usually go about it with a web site or web service are;

•    integrated – i.e. let the web server do it via something like Basic Authentication, Digest Authentication, Windows Authentication.
•    “forms” – i.e. the web server leaves the traffic well alone and something like ASP.NET steps in to make sure that each request carries an appropriate token (cookie) indicating that it has been authenticated. Unauthenticated traffic is usually redirected to a “login page” which harvests credentials and returns a suitable cookie to be replayed on subsequent requests.

Usually, the former is done against credentials managed by Windows whereas the latter is done against credentials managed by the application itself (or by ASP.NET on its behalf).
Where “forms” authentication can get a little odd is where you are using it to authenticate calls to web services and there perhaps aren’t any actual web pages in your application at all.

For instance, you can easily build a Silverlight client that calls web services and then put forms authentication in front of those services. This means that the first request from the client to a service is going to be bounced as it won’t be carrying the right cookie.
That kind of client needs some additional service to call to perform the authentication that’s not an HTML based web page and that’s made easy by ASP.NET offering its membership/roles/profiles services as web services (which I made use of here) so a Silverlight client can call the membership service, get credentials authenticated and then (usually) that translates into a cookie that then authenticates the client as it makes follow-on service calls.

But, that all takes a bit of work to get things in place and so RIA Services comes along and simplifies it by supporting both Windows (i.e. integrated) and Forms based authentication and any other custom scheme that you might want to plug in.
How do they do that then? Abstraction!
RIA Services already has the notion of a service than can be easily exposed to the client side – the DomainService.

In order to support authentication, there’s a derivation of DomainService called AuthenticationBase<T> on the server side. Because it’s a DomainService, the code-generation process will make it available to the client side.
AuthenticationBase<T> looks like;
      
the idea of the generic parameter <T> here is that it’s a class to represent the authenticated user down on the client side and IAuthentication<T> providing the plug-in point.
Whatever information you need to pass around about the user can be added to this class and then it’ll show up down on the client side. The primary example here would be properties that you’re storing in the ASP.NET profile system and there’s an automatic way to wire those up (later). Anyway, you’re more than likely to want to know the user’s name and application roles on the client side so T here is constrained to be an IUser which looks as above;
Running the code generation process on these server-side bits causes client side bits to get emitted;
•    a User class that’s derived from Entity, but also implements IPrincipal, IIdentity
o    I talked about Entity a lot in this previous post – given that this is data returned from a DomainService, it makes sense that it derives from Entity
•    A class derived from AuthenticationDomainContextBase
at first, it doesn’t seem so obvious what you actually do with the AuthenticationDomainContextBase class unless you’ve seen these other classes;


So…we can do FormsAuthentication or WindowsAuthentication and we can treat either of these as an AuthenticationService and in doing so we need to plug in a DomainContext of type AuthenticationDomainContextBase and so that’s where our generated class plugs in.
AuthenticationService looks like;

and so I can write code that uses FormsAuthentication/WindowsAuthentication directly or I can take advantage of some more generation…
If you’ve got a direct link from your Silverlight project to your Web project then you’ll have a generated WebContext class (derives from WebContextBase) and that class;
•    implements IApplicationService which means you can drop it into your Application class’s ApplicationLifetimeObjects collection
•    has a static member on it called Current which returns the current WebContext so you can easily grab it from anywhere
•    has a property on it called Authentication of type AuthenticationService so this provides a slot where it’s easy to store/retrieve whatever authentication service you’re using
if you’ve used the “Silverlight Business Application” template then you’ll have seen that this template automatically instantiates a WebContext for you ( check out App.xaml.cs ) and automatically instantiates a FormsAuthentication instance and drops it into the WebContext’s property Authentication. You could equally well do a similar thing in XAML or code yourself like this XAML example below;


and with that in place it means I can use WebContext.Current.Authentication to get to my AuthenticationService whenever I want.
If you don’t have a direct link then it’s pretty easy to create a WebContextBase derived class yourself.
Either way, I’ve got an AuthenticationService (FormsAuthentication/WindowsAuthentication) that I can write code against. So, how’d you make this work in specific scenarios around both Forms authentication and Integrated authentication?
Now say I have a following service; and so I can call this from the client-side;

but, having done nothing about authentication I hit an immediate problem which looks to resolve to;

 
but I’m not trying to authenticate! What’s going on here? Well, if I look at my IIS set up then what I have is;
•    Default Web Site->Auth Site
and I have both of those set up to allow both anonymous and basic authentication;

 
and that’s causing me “a problem”. As far as I know, the problem it’s actually causing is to the webHttpBinding which is trying to “guess” which of these 2 options I want it to use. What if I change my configuration to try and help it out?
That seemed to stop WCF trying to guess about whether I wanted “Anonymous” or “Basic” and I’m now running unauthenticated calls from my client to my service.
I guess it’s time to switch on some authentication then…
Requiring Authentication
I can declaratively demand that access to my entire service or specific operations is authenticated by applying RequiresAuthenticationAttribute and be specific about roles (defined by ASP.NET roles/Windows) by using the RequiresRoleAttribute and I can do that to either the entire domain service class or specific methods on it as in;
and now my client can no longer make calls to that particular operation ( fails with an “Access Denied” error as you’d expect ) so I need to get my client to authenticate.
On the server-side, I can switch on Forms authentication in my web.config;

and then I figured that I might be able to get away with just using the FormsAuthentication class on the client side without even making use of an Authentication Domain Service because I’m not doing anything fancy with users and so on. So, I tried;

but that’s no good. I get an exception;
The DomainContextType is null or invalid and there are no contexts generated from AuthenticationBase<T>.
Ok – fair enough. I add a new project item;


to add a Authentication Domain Service to my service-side library project (AuthRIALibrary.Web) and called it MyAuthDomainService and that causes the generation of a MyAuthDomainContext on the client side and then I can authenticate and (on success) call my service operation;
and that works fine for me. Now, because of the way I’ve structured my projects I don’t get a WebContextBase-derived class generated for me in my main Silverlight application project but I can duplicate the generation process easily enough in that project;


then I can ( maybe ) drop some of this into my App.xaml;

and then that makes the rest of my code a lot simpler;

( although not exactly equivalent code to what I did before but the intent is the same and now I can rely on MyWebContext.Current and not worry too much about what kind of Authentication service it’s providing ).
It’s not a great idea to do Forms authentication over HTTP though so it’d be better to make sure that I change the MyAuthDomainService class to state that it needs HTTPS as a requirement for use;
and then my client code stopped working because it was trying to access the forms authentication service via https://localhost and that’s not going to work.
How did the client suddenly know it was meant to use HTTPS for access to the authentication domain service? A sneaky small trick – if you have RequiresSecureEndpoint=true set then the client code generation process spits out a slightly different constructor for your class derived from AuthenticationDomainContextBase. In my case, this is my MyAuthDomainContext class and the modification in the generated code is;
that true flag in the generated code says “Use HTTPS” and isn’t present if the RequiresSecureEndpoint isn’t set on the server.
How do I get my client code back to working? Up until now I’d be letting Visual Studio set the start page for my solutions but this means that it uses http://localhost so I need to switch that start page because localhost isn’t a machine name that I have SSL certificates for. My machine name is kumardh and I have certificates for that name.
I switched my start page for the application to have a proper machine name in the URL http://kumardh/… and then (not surprisingly) I hit a cross-domain issue because my application is being served up over HTTP and it straight away goes and does this HTTPS request in order to do its Forms authentication via MyAuthDomainContext.
Time for a cross-domain policy file (to allow the cross-scheme request). Mine looked like;

and that’s enough to say that apps from my machine are allowed to do cross-scheme into my AuthSite virtual directory.
On the service-side, I can get hold of the authenticated user easily enough;

just like I can easily get to the user on the client side via MyWebContext.Current.User (see previou lumps of code).
If I also want to program against the Profile service from ASP.NET and store data on a per-user basis without having to write custom code then I can (e.g.) switch on the service in my web.config and add a per-user property such as;

and then add ( service-side in my RIAAuthLibrary.Web project ) to my User class which Visual Studio generated when I added an Authentication Domain Service;
and then that becomes available to me from the client side ( minus any kind of error handling );
so that’s all good and I’m doing read/write on those properties and persisting the changes back to the server. What about integrated authentication?
Integrated Authentication
I like to start simple so to experiment with integrated authentication I first backed out the HTTPS requirement on my service;

 
and then I edited my web.config in order to specify that I was using Windows authentication and that I wanted to use Basic authentication along with that; and also to guide WCF;
then I made sure that my IIS configuration was set up to allow (not force) Basic authentication for my site;

Then I changed my App.xaml to use WindowsAuthentication rather than FormsAuthentication;

Then I hit a snag when running my client side code because running it produces an exception;
A first chance exception of type 'System.NotSupportedException' occurred in System.ServiceModel.DomainServices.Client.Web
Additional information: Windows authentication does not support logging in.
so it seems like if you’re using integrated authentication then you are going to let the “transport” figure out the credentials rather than providing them programmatically and so you don’t explicitly Login with a user name and password.
Silverlight has 2 stacks for HTTP – client and browser with different capabilities. It’s a trade-off as to which one you use. Specifically, here, the client stack is capable of doing integrated authentication by either allowing the transport to gather credentials or by having them provided by code. The browser stack does not support the idea of credentials coming from code. I suspect (to get ASP.NET cookie integration) that RIA services is running over the browser stack and so you can’t pass credentials when doing an integrated authentication.
I need to change my client-side code a little in order to call LoadUser rather than Login – it’s “fun” to note that even though I’ve moved to integrated authentication, I can still rely on the ASP.NET profile service and get custom per-user data represented on the client side by the generated User class and so most of my code still works if I call LoadUser() instead of Login;
MyWebContext.Current.Authentication.LoadUser();
Personally, I’d perhaps want to put the difference between FormsAuthentication and WindowsAuthentication behind some other class that abstracts the differences here around Login/LoadUser.
When I run that code, I see the browser prompt;
and then the client-server interaction happens and I can see in Fiddler what’s going on;


Great. I can switch to using Windows authentication by changing my web.config;
and re-configuring IIS;


and that seems to work fine – it does not involve me typing in credentials because (in my setup) my web server and my client machine are in the same domain and I’m already authenticated so Windows just does the “right thing” here.
Note – I also tried changing my configuration to “digest” here and for whatever reason I couldn’t get that to work – not sure that’s going on with my configuration there.
Now, naturally, if I’m going to use something like “Basic” then I need to secure it with HTTPS.
So, I switched my configuration back to “basic” and then altered my authentication service to demand HTTPS; and in web.Config;
and then things went slightly awry for a while in that I hit an exception;
Additional information: Could not find a base address that matches scheme https for the endpoint with binding WebHttpBinding. Registered base address schemes are [http]
and it took me a little while to figure out how to get past it and I’m not entirely sure that I got past it in the right way.
What I did was set the security mode up there back to None.
I’m not nearly 100% sure on this one. I’ve told the client to always use HTTPS so that seems fine but with mode=”None” it feels like I might be allowing my service to be called over HTTP but then I’ve got the RequiresSecureEndpoint setting set to true. So am I configuring this the right way? Not sure!
I’ll come back to this if I figure it out better.
Providing a .SVC File
Up until now, for integrated authentication I’ve been setting up IIS so that my site is using;
•    Anonymous + Basic
•    Anonymous + Windows
with the rationale being that I want the unauthenticated user to be able to get to my HTML page and my Silverlight XAP but then I want to have my Silverlight application’s calls across to my domain services to be authenticated and I’ve been using the standard webHttpBinding in my web.config to ensure that WCF knows whether I’m actually using Basic/Windows;

 
If I was using WCF on its own and wanted to do something like basic authentication over HTTPS what I usually do is drop my service SVC files into a folder called something like secure and then I set up IIS to demand HTTPS and basic authentication for that particular folder (and I config up WCF to tell it that’s what I’m doing).
But how to do that with RIA Services where there are no SVC files to drop into a folder?
Whilst RIA Services usually dynamically generates a .SVC file (see earlier post) you can author them manually yourself.
If I create a folder called Services in my web site then I can create SVC files for my services ( the authentication service and the domain service ) naming them in my case;



and the content of one of those files looks like; and I can alter my main web.config to remove the service definitions;
and then I can have the web.config in the Services sub-folder;
Note that in that sub-folder, I don’t need to include that webHttpBinding section because I’m going to configure this folder in IIS to force Basic authentication and HTTPS so there’s no “confusion” for WCF as to whether I want Basic auth or not.
Note that I also had to add a reference to System.ServiceModel.DomainServices.Hosting in order to be able to use the right service host factory here.

5. Silverlight and WCF RIA Services – Validation

One of the strengths of WCF RIA Services is in its capabilities around the application of common validation logic on both the client tier and the service tier. I am using the following model for validation example -
In our particular example, the Product class has a MetadataType attribute applied to it which states that the generated nested class Product.ProductMetadata can also contribute metadata to the Product class itself which is being generated for me by the Entity Framework generation process.
Lets apply a validation attribute such as this Range attribute below to the ProductMetadata property called UnitsOnOrder and the implication is that I want to apply that Range attribute to the UnitsOnOrder property of Product;
There are a number of pre-canned validation attributes in System.ComponentModel.DataAnnotations such as;
•    Range
•    Required
•    RegularExpression
•    StringLength
all of which are derived from ValidationAttribute.
Now, with my Range attribute applied on the service-side, let’s imagine that I have some client code that tries to create a new product like this sketched client-side code below does;
Attempting to insert an invalid product like this ( invalid because of the 101 units on order ) is going to result in errors being returned from the call to SubmitChanges and running the code gives me;
 
In this case, the invalid data never made it to the service. So we have following posibilites -
1.    It can be caught on the client when we call SubmitChanges()
2.    It can be caught by the service when a SubmitChanges() call arrives on the service-side
3.    It can be caught on the client long before we ever call SubmitChanges()
 
Validation Around SubmitChanges()

My attempt to call SubmitChanges() never left the client side because a ChangeSet was constructed ( containing my single insert of a single invalid Product ) and then that ChangeSet was validated and the failed validation result is immediately returned to the client rather than wasting a trip to the service.
What if I apply some validation logic that’s a little more custom? As a starting example, I can replace my Range attribute with a CustomValidation attribute like this one;

Now, I have a choice about how I build the type MyValidator on the service-side. I can either put it into a regular code file and, in that case, the validation will only be applied on the service-side. So, if I write MyValidator as;
and then re-run my original client side code against this then the validation will not happen on the client because the code generation process has not copied the MyValidator type to the client and nor has it generated the CustomValidation attribute on the Product’s UnitsOnOrder property.
Consequently, the call to SubmitChanges() will cross the network and rely on the service-side to do the validation.
When that call reaches the service-side, my DomainService (ProductService) will get instantiated and then it will go through its lifecycle of;
Initialize->Submit->AuthorizeChangeSet->ValidateChangeSet
and when my ChangeSet hits that ValidateChangeSet() method, the base class implementation will essentially use the System.ComponentModel.DataAnnotations.Validator class to validate the entities which in my case will cause a validation failure.
Once again the end result is that I get an error back to my call to SubmitChanges but this one actually came from the service-side unlike the previous example where there was no need to invoke the service.
If I want my new custom validation to occur down on the client, I can easily arrange for the MyValidator type to be shared with the client. I just rename its source-code file to include a .shared as in;
  

and now the code generation process will work differently and make sure that on the client side two additional things happen;
1.    The type MyValidator is copied to the client side and is built into the application there.
2.    The same CustomValidation attribute will also be applied to the UnitsOnOrder of the Product entity
so now when I run my client-side code I’ll get validation once again on the client and the service-side will never be invoked.
There are other ways of doing custom validation. On the service-side, I could alter the definition of my Product metadata class so that it looked something like; and then I can change the definition of the MyValidator type;

Once again, if I place this into a file with a .shared.cs extension on it then it will run both client and service-side whereas if I place it in a file without a .shared.cs extension then it will only run client side.
If I only want the validation to run service-side then another option is to remove the CustomValidation attribute from my Product class and, instead, modify my DomainService itself. Here I ll modify its InsertProduct method to include a CustomValidation attribute as below;
 
 Then I get that same custom validation of my Product instance but, in this case, that’s only on the service-side and it’s only for Insert operations because that’s the only place where I have applied the attribute. Clearly, I could also apply it to Update and Delete or have different validators plugged in on those operations if I wanted that flexibility.
Another option about applying custom validation is to build my own class derived from ValidationAttribute in order to have my own library of custom validation attributes. As an again, contrived, example I might build an attribute such as this one which makes a fairly weak attempt to ensure that a numeric value is an even number; and I could then apply that on my ProductMetadata class to something like UnitsOnOrder;
Once again, if I put the code for my EvenNumberAttribute into a file with a .shared.cs extension then it will be run on both the client and the service side whereas if I don’t have a .shared.cs extension then it will only apply on the service side.
Validation Before SubmitChanges()
If I revert back to my original setup and fragment of client-side code, reproduced below, which was being validated by a model which had a Range attribute on the UnitsOnOrder property;
then it’s worth nothing that the Product that I create and populate is invalid from the point at which I set the UnitsOnOrder to a value of 101 and the entity itself “knows” that it is invalid from that point.
This is because the client-side generated Product class derives from Entity and is code-generated such that every property setter calls the base class ValidateProperty() method every time the property value changes.
What does ValidateProperty do? Ultimately it ends up in a call to Validator.ValidateProperty from System.ComponentModel.DataAnnotations and it’s that method which will perform the validation based on the validation attributes that it “sees”.
Consequently, as soon as the call to the UnitsOnOrder property setter has completed, the Entity will already be marked as invalid and I could have checked for validation results by doing something like;
 
which displays a MessageBox showing that the Entity knew that it had errors as soon as the property had been set to an invalid value and long before I got anywhere near to calling SubmitChanges() on the DomainContext.
But, in Silverlight this would be a pretty lame way of gathering up the validation problems and reporting them to the UI because the Entity base class implements INotifyDataErrorInfo and so it is fully capable of returning validation errors to the UI ( both synchronously and asynchronously ).
If I create the most basic of UIs around this data; and if I then have code which sets up a DataContext with an invalid Product; then, because of INotifyDataErrorInfo and because I set the NotifyOnValidationError on my bindings then the validation problem will show up immediately in the UI;
  

and I could also drop a validation summary onto the same form to display that information and, just by virtue of putting that ValidationSummary into the same parent container (in this case, a Grid) it picks up the validation problems as in;
 

Now, I could have some kind of “Submit Changes” button that enabled/disabled itself based on the HasValidationErrors property of my Entity (or I could do something more complex and have a SubmitChanges ICommand that did a similar thing) as in;
 
where negateConverter is just a converter that flips over a boolean value and so that’s nice because it means that my UI won’t let my SubmitChanges call execute if the underlying Entity has validation problems.
That’s going to work out “ok” if I am doing per property validation because the generated Entity-derived class on the client side calls Entity.ValidateProperty every time a property changes.
But what if I have custom validation on the Product type itself. For instance, what if I have this routine that wants to validate a whole Product instance rather than just a single numeric property value?
and I make sure this is available to the client-side by putting it into a .shared.cs file and I associate it in my service-side metadata code with the Product type as in;

then what happens client side when I have a UnitPrice, UnitsOnOrder combination that results in > 1000.0? Nothing.
Why? Because nothing in the framework is going to attempt to validate the whole Entity instance. There is nothing in the generated setters that will cause this validation to run. So, what I see in my UI is;
  

Now if I actually make a call to DomainContext.SubmitChanges then it will validate the Entity and that will fail. That is, if I put some code behind my “Submit Changes” button like;
 
 then I see that my validation is being called on the client-side and that it is failing. However, my UI still doesn’t display anything.
Why? Because the errors that I’m raising from my validation routine are not being associated with any particular property of the Entity. They are being associated with the “whole entity”. The interface INotifyDataErrorInfo associates the [null/string.empty] property name with errors that are meant to relate to the “whole object”.
The bindings I have set up in my UI are only set up to look for validation problems with properties (ProductName, UnitPrice, UnitsOnOrder).
If I want to get validation problems for the “whole object” displayed in the UI then (AFAIK) I need to have a binding that is interested in the “whole object” such as below on line 4;
 
notice that the Grid binding its own DataContext back to its own DataContext doesn’t really achieve anything other than to switch on the NotifyOnValidationError and that causes my UI to do the right thing in the sense of;
  

Ok – so I can get my “whole entity” validation errors to show up on the screen but only after I call DomainContext.SubmitChanges or execute equivalent code – I think equivalent code might be something like;
 
which left me wondering whether there’s some way I can force this sort of code to run whenever my UnitPrice or UnitsOnOrder property value change in order to avoid having to call SubmitChanges to find out about those validation errors.
Some routes that I tried or at least thought about;
1.    I can’t (AFAIK) interfere with the code generation process so I don’t think there’s anything that I can do to force the whole entity to be validated when those 2 properties change by that route.
2.    I figured that I might try to hack together a custom validation attribute which didn’t actually do any validation but, instead, tried to get the whole entity validated and then I could drop that attribute onto the 2 related properties so that they would force the revalidation of the whole entity.
I tried to sketch out (2) above. The “trick” is that I can only get my code invoked as a result of a code-generated call which calls Entity.ValidateProperty and passes the prospective property value which has not yet been set on the underlying object instance. So perhaps I can sketch out an attribute like;
 
and note that this is really just trying to call TryValidateObject which will call any “whole entity validation” that I have associated with my entity and it also tries (hack!) to pass down a hint in the ValidationContext.Items collection of what the proposed new value for the property is. I could drop that attribute onto my UnitsOnOrder and UnitPrice properties;
 
and then I drop into a not-too-pleasant ValidateProduct routine on my ProductValidator class;
and you’ll notice that this is trying in a very brittle way to do the right thing in that it is trying to serve two purposes';
1.    Whole entity validation when called from a place like SubmitChanges when it is ok to inspect the actual value of the two properties UnitPrice/UnitsOnOrder on the instance.
2.    Whole entity validation when called from a generated property setter when there is a changed property value still “in flight” and we have to try and figure out which property it is and what the value is going to be.