Raw Notes-OData Web Services

Thursday, March 01, 2012 / Posted by Luke Puplett / comments (0)

OData

EF

Linq-to-SQL

IQueryable<T> (can be collection.AsQueryable() but collection must be the whole set)

Custom Provider

DataServiceKeyAttribute on entity defines the property that has the unique id.

Add WCF Data Service item to project.

Gives service class deriving from DataService<T> where T is provider (IQueryable)

In InitializeService override, set config options for default security.

That’s it. /Actors will correspond to public IQueryable<Actor> Actors member on provider!

Filtering and paging etc. will just work via URL.

An OData service is a RESTful WCF service so it supports custom operations, like any other service operation, and can use WebGet and WebInvoke for GET, PUT, POST, DELETE

Adding a new resource:

// in ServiceOData : DataService<T> class
[WebGet]
public IQueryable<Person> TopPeople()
{
return (from p in CurrentDataSource.people
let rating = p.reviews.Average(r => r.rating)
where rating > 9
orderby rating
select p).Take(20);
}

Then provide access via

config.SetServiceOperationAccessRule(“TopPeople”, ServiceOperationRights.All);

Method/operation parameters passed in by URL query string.

Filters and Interceptors

Query interceptors apply to GET operations and do business rule validation, security, further filtering. E.g. only return records for the customer.

Change interceptors apply to POST, PUT, DELETE and do security, rejection, blasphemy.

Implement both with operations on the data service class using attributes, or by entity in general.

[QueryInterceptor(“people”)]
public Expression<Func<person, bool>> FilterPeople()
{
return (p) => p.department == “IT”;
}

[ChangeInterceptor(“people”)]
public void FilterPersonChange(person r, UpdateOperations ops)
{
if (ops == UpdateOperations.Add && (p.Name == “Dave CEO”))
throw new DataServiceException(400, “No-one updates the boss.”);
}

Labels: , ,

Raw Notes–WCF 4.0 New Features

Wednesday, February 29, 2012 / Posted by Luke Puplett / comments (0)

WCF 4.0 Notes

Default Endpoints

Base addreses + contracts (HTTP, TCP)

WCF creates endpoints based on info it has, above.

Default Bindings - binding with no name becomes default.

Default Behaviours – behaviour with no name becomes the default.

Standard Endpoints – built-in endpoints in common configurations.

File-less Activcation – Config file defines what is usually in the .svc file, but your service is still /blah.svc

REST

HTTP Cache now works.

Message Format selection is now done with HTTP headers as it should be.

WebFaultException now automatically does HTTP codes and everything.

ASP.NET routes means you can remove .svc file.

Service Discovery

Ad-hoc mode is broadcast based, enquire and announce to local subnet.

Managed mode is a central proxy/catalog.

Message Routing

Rules-based and transport neutral so HTTP can go via MSMQ.

Server in DMZ and routed to inside.

Bridge protocols (e.g. HTTP > net.tcp)

Well-known public façade for many services.

Load balancing, routes can be round-robin or fallback on timeout.

Failover.

Multicast one-way message to receivers that need to know.

WCF 4.0 Config Model Updates

Default Endpoints

One per contract/base address combination. This is done via protocolMapping, which can be tweaked.

If any endpoints are configured, then this overrides the auto config. So adding a MEX endpoint in code will screw it up, so you need to call host.AddDefaultEndpoints();

Default Bindings & Behaviours

So you can now setup defaults in machine.config and override in web.config.

Common behaviours are not new to 4.0 but these allow additive behaviours and are only allowed in machine.config <commonBehaviors>

Standard Endpoints

Use the kind attribute on the endpoint, mexEndpoint, discoveryEndpoint, webHttpEndpoint for REST.

<endpoint kind=”webHttpEndpoint”> ßfails because it needs contract

<endpoint kind=”webHttpEndpoint” contract=”lala”>

<endpoint kind=”mexEndpoint” address=”/mex”> ß needs address

No other configuration needed.

WCF 4.0 REST Updates

Automatic Help page shows available verbs and actions, <webHttp> helpEnabled=”true” and visit blah.svc/help

Caching works like this:

[AspNetCacheProfile(“CacheFor10Seconds”)]
[WebGet(UriTemplate=XmlItemTemplate)]
[OperationContract]
public ...

Profiles are added like this (aspNetCompatibilityEnabled=”true” must be set):

<system.web>
<outputCacheSettings>
<outputCacheProfiles>
<add name=”CacheFor10Seconds” duration=”10” varyByHeader=”Accept” varyByParam=”” />

Message Format Selection

Needs switching on:

<system.serviceModel/standardEndpoints/webHttpEndpoint/standardEndpoint name=”” automaticFormatSelectionEnabled=”true” />

WCF Routes

// Global.asax called from Application_Start
private void RegisterRoutes()
{
var f = new WebServiceHostFactory();
RouteTable.Routes.Add(new ServiceRoute(“Data”, factory, typeof(MyService)));
}

Labels: ,

Helpful docs when hardening an IIS web server

Sunday, November 21, 2010 / Posted by Luke Puplett / comments (0)

While clearing up some crap on my desktop I came across a note listing some documents I’d used when preparing my web server for co-location and exposure to the harshness of the public internet.

How To: Harden the TCP/IP Stack
http://msdn.microsoft.com/en-us/library/ff648853.aspx

TCP Receive Window Size and Window Scaling
http://msdn.microsoft.com/en-us/library/ms819736.aspx

How To: Protect Forms Authentication in ASP.NET 2.0
http://msdn.microsoft.com/en-us/library/ff648341.aspx

How To: Perform a Security Deployment Review for ASP.NET 2.0
http://msdn.microsoft.com/en-us/library/ff647403.aspx

How To: Use IPSec for Filtering Ports and Authentication
http://msdn.microsoft.com/en-us/library/ff648481.aspx

How To: Use IISLockdown.exe
http://msdn.microsoft.com/en-us/library/ff650415.aspx

Labels: , , ,

Note to Self: Don't Let WCF (SvcUtil) Reuse All Libraries

Friday, July 23, 2010 / Posted by Luke Puplett / comments (2)

Another short post to remind myself for when I inevitably forget some of the nuances of my nemesis, WCF. This one regards the error below:

Warning 1 Custom tool warning: Cannot import wsdl:portType Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter Error: List of referenced types contains more than one type with data contract name 'Recorder' in namespace 'http://schemas.vuplan.tv/2008/11/vuserv/entities/core/user'. Need to exclude all but one of the following types. Only matching types can be valid references: "S26.Vuplan.Core.User.ClientRecorder, S26.Vuplan.Client.MediaCenter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" (not matching) "S26.Vuplan.Core.User.Recorder, S26.Vuplan.Core, Version=1.0.2.0, Culture=neutral, PublicKeyToken=80726da9f797f65e" (matching) XPath to Error Source: //wsdl:definitions[@targetNamespace='http://schemas.vuplan.tv/2008/11/vuserv/user']/wsdl:portType[@name='IUserService']etc. yeah yeah.

I don't know why the WCF team didn't add a proper UI to this. To see and configure the mappings between a service and your client app, as well as a more wizardy interface and perhaps a more verbose "here's what I'm doing now" style feedback system would save hours.

I have a core library in which a Recorder object lives. This core library is used on server and client and defines many entities and other pan-application helpers and types. The problem comes when I define a derived type of Recorder for the client to use, which has more client specific logic in it. I want to new up a ClientRecorder and then pass the thing back up to the cloud, so I add its Recorder DataContract, and that's when it all falls apart.

The SvcUtil has been instructed to reuse types in all referenced assemblies, so when it tries to map a Recorder contract to one of my types, it can't tell if I want to use the one in the core lib or the new client one.

I could rem out the DataContract line and reimport, this'd work, but the fix is to make sure that I don't try and reuse types in my client assembly.

The config page for the Service Reference doesn't allow excludes, so I have to tick almost all assemblies except the ones I definately know don't contain serializable classes. See pic:

Service Reference Reuse

By doing it this way, I should be able to hit Update at any point in the future and not suddenly be thrown out by the error and the massive knock on effect it has to compilation.

Labels: , ,

Adding a UserAgent to WCF Clients

Thursday, July 22, 2010 / Posted by Luke Puplett / comments (0)

A quick post to show how to add a UserAgent to a WCF call so that it can be inspected on the server side, perhaps to see which versions of clients are calling your service.

And completely free of charge, I'm including some extraneous code I use to show how service method calls can be made without having to jump through hoops every time.

The code

        public T CallServiceMethod<T>(Func<T> methodCall, bool canExpectNull)
        {             
            T response;

            using (OperationContextScope scope = new OperationContextScope(this.ServiceClientChannel))
            {                 
                HttpRequestMessageProperty p = new HttpRequestMessageProperty();
 
                p.Headers.Add(System.Net.HttpRequestHeader.Cookie, this.AuthenticationCookie);
 
                p.Headers.Add(System.Net.HttpRequestHeader.UserAgent, typeof(ServiceHelper).Assembly.FullName);
 
                OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, p);

                this.IncrementCallsInProgress();
                try
                {
                    response = methodCall.Invoke();

The blurb

I'm sorry about the broken lines - I so nearly picked a full width Blogger template, too. The method above essentially wraps a delegate invocation in some calls into WCF's OperationContext which adds the headers. It's interesting to look at the OperationContext in the debugger, much as you probably did with the HttpContext when first looking at an ASP.NET app - its sort of the equivalent but in reverse.

The method's ending isn't shown, I'm lazy like that, but it just catches errors, the finally block decrements the calls-in-progress counter and there's some logging.

On the server, I use the HttpContext.Current.Request.UserAgent string to log which client versions my customers are running. Useful.

Notice that I'm also adding a cookie which I store in the class that this method is part of. I'm using the built-in AuthenticationService which uses Forms Authentication and thus, cookies. This is not required in Silverlight as the IE stakc stores and reapplies appends any cookies received, automatically.

To use this method, I instantiate my service client proxy and then call ServiceHelper.CallServiceMethod( () => { return proxy.SomeMethod(xyz); });

The proxy call is thus invoked within the context changes above.

Labels: , , ,

Setting-Up WCF Over SSL on IIS 7.x

Monday, July 19, 2010 / Posted by Luke Puplett / comments (1)

This is a short post is about the steps I had to take to switch an existing test WCF service over to a secure staging version that more closely mimics how it’ll be in the production environment. I hope to include some things they didn’t tell you in the instruction manual, mainly concerning the use of test certificates.

It’s stuff like this – configuring a secure web service – that makes me dislike WCF and IIS quite a lot. I liked Web Services, and Remoting, I even found raw sockets surprisingly easy but WCF is hard work. It’s the sort of thing that needs its own UI, management tools, and server, but to do this would arguably constrain its power.

  1. Add a self-signed certificate to the server by opening IIS Manager, highlighting your server name in the left pane and locating Server Certificates on the right and choosing Create Self-Signed Certificate then following the instructions.

  2. Add a new binding to your site for HTTPS and note that there’s no option for the host name.

  3. WCF cannot handle multiple bindings to the same scheme, as IIS and ASP.NET sites can, so if your WCF service is hosted downstream of your main site, such as from a virtual directory underneath your root domain and site, then add the following to your web.config which will filter the bindings so WCF sees just two:


    <system.serviceModel>
    <serviceHostingEnvironment>
    <baseAddressPrefixFilters>
    <add prefix="http://wwwdev.dom.co.uk" />
    <add prefix="https://wwwdev.dom.co.uk" />
    </baseAddressPrefixFilters>
    </serviceHostingEnvironment>
    </system.serviceModel>
  4. And now the bit that seems never to be explained and doesn’t seem to merit a proper UI in IIS, binding the certificate to the host header. Run this at a command prompt (one line):


    appcmd set site /site.name:"Main Site" /+bindings.[protocol='https',bindingInformation='*:443:wwwdev.dom.co.uk']
  5. Do not remove the original HTTPS binding. When I did, I got this error:

    An error occurred while making the HTTP request to https://wwwdev.dom.co.uk/xml/AuthenticationService.svc. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.

  6. Now, if you’re using the built-in AuthenticationService, in your web.config or web.staging.config, make the following change/addition:


    <system.web.extensions>
    <scripting>
    <webServices>
    <authenticationService enabled="true" requireSSL="true"/>
  7. Still in this document, find the binding element for the service and set it to use Transport security – the bottom lump of mine looks like this:


    <binding name="ssl">
    <security mode="Transport" />
    </binding>
    </basicHttpBinding>
    </bindings>
  8. Close and save all that and then make the same change on the client. Personally, I don’t use config files for public ‘out there’ apps so the change is made within a service client factory using the following code:


    if (withSsl)
    basicBinding.Security.Mode = BasicHttpSecurityMode.Transport;
  9. Add the following non-WCF specific code at some point in your app which essentially just accepts any certificates as valid even if they’re downright dodgy (so make sure not to let it leak into production).


    #if DEBUG || STAGING
    System.Net.ServicePointManager.ServerCertificateValidationCallback = (se, cert, chain, sslError) => { return true; };
    _log.Warn("A pre-release option has been set: server certificates are no longer being checked for validity by this client app.");
    #endif
  10. You do not need to add code that modifies the Authentication settings for the ServiceCertificate on the ClientCredentials object of a service client (ServiceBase<T>).

  11. Now test your service. You may want to use a tool like Fiddler to inspect the HTTP traffic.

Labels: , , ,

Empty DataContract Causes Misleading Error

Wednesday, February 17, 2010 / Posted by Luke Puplett / comments (1)

After my last post on this subject you'd have thought I'd learnt a lesson but the error message and sheer coincidence of the error being about a class I happened to be working on at the time meant it took me 10 hours to unearth the problem.

After updating a service reference that had been left for some months, I received the following IDE warning:

Custom tool warning: Cannot import wsdl:portType

Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter

Error: Referenced type 'Steelcore.Spanware.QueryBlock, Steelcore.Spanware, Version=2.0.1.0, Culture=neutral, PublicKeyToken=80726da9f797f65e' with data contract name 'QueryBlock' in namespace 'http://schemas.evoq.co.uk/steelcore/2009/03/spanware' cannot be used since it does not match imported DataContract. Need to exclude this type from referenced types.

Because I had just been adding new web methods that use QueryBlock, and because I am working in Visual Studio 2010 RC1 it was difficult to know if this was a genuine error, afterall, I'd not changed the Steelcore code for ages and it used to work.

Troubleshooting

I'll spare you the details on all the stuff I tried that didn't work. Getting to the bottom of it was a case of isolation.

To remove the local client project from the equation I created a new WCF Service app in Visual Studio, added the reference to my Steelcore library and configured the service with one web method/operation contract that takes the offending class QueryBlock as its sole argument. I then created a new client app, referenced Steelcore and the WCF service. This caused the same warning.

I then opened the Steelcore solution and commented out some of the DataMember attributes on the QueryBlock and rebuilt. Went back to my little test rig and rebuilt and updated the service references. Warning gone.

Obviously one of the types used in the now defunct DataMembers is causing the issue, probably my LooseTypedCriteria class, so I changed the WCF service to accept one of these as its sole argument and found the warning from SvcUtil was talking about Steelcore.Spanware.Criteria.

I commented out some of the DataMembers on Criteria and repeated the process. It all referenced fine, and so again, one of those members is using a class that SvcUtil doesn't like. I noticed one was an enum and then I recalled my enum DataContract problems.

Solution

Sure enough this enum had a DataContract but no DataMember attributes applied. This makes it effectively empty. As before, the solution was to remove the DataContract and let .NET figure out the contract automatically.

Labels: ,

What the &#x0

Friday, October 02, 2009 / Posted by Luke Puplett / comments (1)

The character combination above is no obfuscation for an expletive. Its HTML notation for NULL and I know this for many reasons. Firstly, because it says so here, but also because it ended up being appended to a JSON object I was passing around.

I have a WCF web method that takes a string but its design is to take some entity as XML. Unfortunately, when there’s a big payload XML wrapped in XML seems to cause HTTP 400 bad request to be spat out by IIS or WCF.

Rather than troubleshoot that, and because I need to get on, my brainwave was to switch serializers. So out went my XmlSerializer and in came DataContractJsonSerializer.

Immediately the deserialization routine threw out a message saying something like invalid character \0 in my Json string.

Reaching for Fiddler I inspected the raw data going over the wire. My Json was all there but so too was &#x0;&#x0;&#x0;&#x0; etc. at the end of the object.

I have a helper class which has serialization boilerplate inside and one of the methods takes an array of Char as the raw data to deserialize. Looking at the array of characters as it went in revealed a whole bunch of character 0 elements.

My initial thought was that the object being serialized has an array that has not been trimmed (TrimExcess) and serialization is making an exact representation, excess included.

Trimming didn’t fix it so I wondered if Microsoft’s DataContractJsonSerializer was pushing arrays around and MS had forgotten to trim the excess.

No. My helper class goes like this (this one is for Xml):

public static void Serialize(object serializable, out string xml)
{
    var memoryStream = new SysIO.MemoryStream();
    Serialize(serializable, memoryStream); // delegates to overload
     
    var encoding = new System.Text.UTF8Encoding();     
    xml = encoding.GetString(memoryStream.GetBuffer()); // bug
}

While looking at the MemoryStream instance I noticed its buffer size was the same as the character array length at my service end.

The problem/solution is this: the GetBuffer() method returns the buffer (okay, its obvious now) while the ToArray() method, which is what I should be using, returns just the data. I assume the buffer has automatically sized itself and has spare capacity.

What is unusual is that the problem is only evident when deserializing Json object strings. The empty data is encoded in the raw string so it must have been there when the text was XML, so it must also have been there when I succesfully deserialized it at the service – maybe the XmlSerializer simply ignores character 0 and gets on with the job.

It you don’t have control over the creator of the data, then writing a function to clean the trailing 0s from the end of a string.ToCharArray() would likely fix the issue.

Labels: ,

Enum DataContract Breaks Type Reuse

Wednesday, May 13, 2009 / Posted by Luke Puplett / comments (1)

Problem and Background

A few weeks ago I got a message stating that I needed to add DataContractAttributes to my enums. I can't remember the details but I know I thought it was strange as it was all working without them. I added the attribute and got another message about not having EnumMemberAttributes on the actual enums values. I obliged and the errors went and I thought that was the end of it.

Today, while coding in the client app, I discovered that my types had properties with Specified appended. The suffix is apparently only added when you reference an old ASMX from WCF. But I'm not, so my suspicions were aroused. Furthermore, my setup is that I reference a shared assembly so I shouldn't have generated types at all..!

Solution and Bug

Had I setup some decent tests then I should have spotted the problem as soon as the change was made three weeks ago because - and I really dislike WCF for its ability to throw a curveball in your face every day - the root of the problem became clear when I rolled back and forward my enums.

It appears that the codebase was alright again (no errors) with the version that didn't include the DataContracts on my enums. While in the source, I noticed that I'd missed decorating EnumMember on some of the values.

I then rolled back again to the working snapshot and added DataContract to the enum but did not add EnumMember to anything. The result was that my working codebase broke - that is, when I updated my client service reference, types were generated and not re-used from the shared DLL.

You guessed it: adding EnumMember to all members of the enum with the DataContractAttribute and recompiling, re-updating the reference, fixed it again so I was re-using my shared lib.

This has got to be a bug. The compiler or the WSDL page should be spitting feathers and not letting me continue to code with the corrupted service state.

Update 1

This morning, after settling on the conclusion that I needed to add EnumMember to all my enum values I found that this actually didn't solve the problem and the solution was to remove all DataContractAttributes from all enums which meant foregoing my service having corporate domain namespaces for every single type - although I will look into using the assembly-level ContractNamespaceAttribute attribute.

Update 2

Further tests show that svcutil making a mess of things might only occur when FlagsAttribute is also applied.

Labels: , ,

One Service + Two Client Platforms = Misery

Friday, May 08, 2009 / Posted by Luke Puplett / comments (0)

Aim: I want to be able to transmit a username and password hash and see it easily from within the service.

My idea of Hell is WCF. I liked .NET Remoting and I got on with Web Services, but the unified Windows Communication Foundation is a quagmire of configuration and complexity, not least because its half-merged with IIS, which is sort of merged but not merged with ASP.NET.

Today, I am tackling the issue of using the same WCF Service that my Silverlight client uses, for a fat desktop client.

Making a Meal of WCF and Cookies

The scenario to the uninitiated might look straight-forward, after all I’m connecting two Microsoft .NET-based products to a Microsoft .NET-based SOAP service, all running in the same VS solution on one box.

The problem is that Silverlight runs in the browser and has an authentication scheme which uses its host browser’s HTTP stack and cookies, while the other client, despite being fat, has never even seen a cookie.

To be clear, my WCF services end uses Microsoft’s AuthenticationService to provide Forms authentication behaviour over the HTTP connection between SL client and service, which basically does the cookie creation and response so I don’t have to. This works great but I what about my non-Silverlight clients?

While Jonas Folleso has one solution to the problem, by detaching the authentication cookie and sticking it back on to all outgoing headers, I wanted to take the ‘easier’ route: exposing another service end-point that supports some kind of authentication.

I want to do this because I want my client to sign-in using the SSL secured AuthenticationService, set-up a session with some shared secret key and then in all subsequent requests to my other services, send over a hash of something using the shared secret.

I’m actually writing this as I work on it, so as these words are being typed, I don’t know what to expect.

Step One: Add a new EndPoint and connect to it

I add a new EndPoint to the web.config of my IIS service host, using the same basic binding as the working service, just for simplicity and testing.

<endpoint address="/vpr"
binding="basicHttpBinding"
contract="IUserService"
/>

Lesson - While doing this, I learn that the <baseAddresses> section is pointless on IIS because its IIS and the base address will be wherever the .svc files are.

I copied the chunk of XML that defines the mex endpoint, and like mex and according to MSDN, my service endpoint address will be relative to the base URL which is the svc file, I presume.


Adding a Service Reference to any of the URLs above fails with error saying:


The request failed with HTTP status 400: Bad Request. Metadata contains a reference that cannot be resolved: 'blah'.

Lesson – You only need to point the Add Reference box to the .svc file and the other endpoints are read from the WSDL (you can see this because the client app.config will fill with the server endpoints).

mex is an exception to the rule and can be referenced by putting /mex after .svc, also the discover option doesn’t see the endpoint as being a different service.

This is all how it should be and I think endpoint addresses are actually just ID strings which help WCF route messages into the right worker queue for processing on the server but are structured as URLs to confuse you.

Step Two: Choose a Binding

The aim is simply to choose a binding which puts the plumbing in place for me to transmit credentials. So first up, I try just setting ClientCredentials.UserName to something useful and checking it on the server via ServiceSecurityContext.Current, but get a null ref exception.

I also try disabling anonymous logon from the IIS console in case this is causing my username to be lost, but this causes everything to break – I can’t even connect to get the service description.

Lesson – Ignore the bit about disabling anonymous access.

I persist with the trusty basicHttpBinding because MSDN says:

By default, the BasicHttpBinding class does not provide security. This binding is designed for interoperability with Web service providers that do not implement security. However, you can switch on security by setting the Mode property to any value except None. To enable transport security, set the property to Transport.

I do as it says but I get this error upon updating my Service Reference:

Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http].

The problem is that I don’t want to use HTTPS. Time to try another tack: Message Security, which MSDN tells me

means that every message includes the necessary headers and data to keep the message secure. Because the composition of the headers varies, you can include any number of credentials. This becomes a factor if you are interoperating with other services that demand a specific credential type that a transport mechanism can't supply, or if the message must be used with more than one service, where each service demands a different credential type.

Here goes nothing.

        <binding name="vpr">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>

I refresh my Service References and receive:

BasicHttp binding requires that BasicHttpBinding.Security.Message.ClientCredentialType be equivalent to the BasicHttpMessageCredentialType.Certificate credential type for secure messages. Select Transport or TransportWithMessageCredential security for UserName credentials.

Right then. TransportWithMessageCredential it is, or at least it would be but that of course leads me right back to:

Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http].

An MSDN article on using the ASP.NET Membership Provider reckons I can use WSHttpBinding set to Message Security to transmit a user name, but goes on to talk about adding service behaviours for the membership provider. I will try most of it (as I don’t want to use the ASP.NET MemProv). I put

    <serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"/>
</serviceCredentials>

..in the behaviours element with this in the binding element:

    <security mode="Message">
<message clientCredentialType="UserName"/>
</security>

But this gives this error when adding/updating the Service Reference:


UserNamePasswordValidationMode.Custom requires a CustomUserNamePasswordValidator. Specify the CustomUserNamePasswordValidator property.


I may be on to something... searching microsoft.com reveals an article entitled User Name Password Validator.

So I’ve written a test class called CookielessCredentialValidator which extends System.IdentityModel.Selectors.UserNamePasswordValidator and just throws a NotImplementedException on the only overridable method is has, Validate() and changed my web.config:

<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="App.Web.CookielessCredentialValidator"/>

Upon updating my service reference I get:


Could not load type ‘App.Web.CookielessCredentialValidator’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Cul... etc.

Looking back at the MSDN article I realised that I need to format the type name differently, prefixing my derived class with the name of my service class and maybe the word service after it? Not really clear and the article on customUserNamePasswordValidator provides no help:

Looking further into this, it seems that I must create an X509 Certificate.

Lesson – You can’t send credentials without HTTPS or some other encryption method in the .NET Framework, even if you do have you own method for encrypting the data you wish to put in the username and password properties.

Step Three: Go back to Jonas Folleso’s Blog and do what he did

...and pray that Microsoft changes this nannying part of the framework before I get customers trying to use my service from a platform that can’t fiddle around with cookies.

The End.

P.S. Sorry about the extra space around blockquotes, the Blogger system seems to want to add breaks each and every time I place a carriage return in pure HTML - bizarre and annoying in equal measure.

Labels: , , , ,

Silverlight to Service Layer: Sharing a CoreLib

Monday, April 27, 2009 / Posted by Luke Puplett / comments (0)

Technorati Tags: ,,

We all know that sharing is caring but when it comes to Microsoft’s RIA client you may find sharing is tearing, your hair out. In this post I will explain how you can code a class once but use it in both your WCF service, and the Silverlight codebase that consumes it.

While architecting a cross-browser web app, I made a big assumption: that Microsoft’s RIA platform would be CLR-based and so my types could be passed (via WCF) though all my tiers; with a simple Add Reference from Silverlight, I’d have access to all my business entities. As it turned out, I couldn’t.

True, Silverlight has the CLR we all know and love, but it ain’t the same CLR. While the Add Reference dialog will lead you up the garden path to your full-fat assembly, the sucker punch goes like this...

“You can’t add a reference to AmazingLibrary.IspentAgesWriting.dll as it was not built against the Silverlight runtime. Silverlight projects will only work with Silverlight assemblies.”

So where to go from here? The answer is to share your code files. The VS 2008 IDE (I haven’t looked in 2005) allows you to link a project to source files with the click of its often overlooked combo-button - I know this is often overlooked because I’ve seen others hacking around with their solution files to achieve the same thing.

 
Right click on the Silverlight project or a folder you have within it and choose this option:

01.Add Existing Item Menu

 
Then take the Add dialog to where you store the code files for your full-fat assembly or types but instead of hastily stabbing at the Add button, drop it down and choose Add As Link:

02.Add As Link Menu

 

You can highlight and link multiple files using CTRL, although once linked you will need to be aware of a few more things.

  1. All edits are shared - because its now linked - but the VS editor will be ‘wearing the context’ of whichever type of project the file was opened from.

    If you double-click the file under your Silverlight project tree it will impose the Silverlight context, such as intellisense, references from the Silverlight project and stuff that just isn’t included in the skinny SL CLR.

  2. You may also need to use the new SILVERLIGHT compiler keyword to section-off lumps of code that don’t compile in SL and section-in alternatives that do.

    #if
    !SILVERLIGHT
        using FullCLR.Types
    #endif

  3. If, like me, you’re sharing entity types for marshalling between a WCF service and a SL client, you may need to add data contract names and namespaces and then update your service references. Of course, you only need to add this once on each shared class.

    /// <summary>

    /// Represents a finite period of time with a start and end.
    /// </summary>
    [DataContract(
        Name = "TimeRange"
        Namespace = "http://schemas.co.com/2008/11/entities")]
    public sealed class TimeR...

    When you hit build, the compiler’s going to ensure that the same data contract metadata ends up in both the service and the client libraries and so when you add a service references, the proxy should map these types rather than generate classes.

     

Note that sharing entities in this way may not be suited to your design philosophy or coupling strategy and that code in the classes that forms the Silverlight client will be publicly available for scrutiny. In my own project I use this technique for ‘hollow’ data contract entities that otherwise contain no business logic.

Luke

Labels: , , ,