2

I've setup a site with forms authentication and AspNetCompatibility enabled. The actual client is a silverlight application, and works fine, however I want to unit test the application separately using normal .net to exercise the service (live system for methods without side-effects). However, when I stop using Silverlight and start using full .net it doesn't remain authenticated

In a web service I have:

[OperationContract]
public bool Login(string Username, string Password, bool isPersistent)
{
    if (Membership.ValidateUser(Username, Password))
    {
        FormsAuthentication.SetAuthCookie(Username, isPersistent);
        return true;
    }
    else
    {
        return false;
    }
}

[OperationContract]
public bool IsLoggedIn()
{
    return HttpContext.Current.User.Identity.IsAuthenticated;
}

Then in a test method on the client I call it like so:

Assert.IsTrue(Client.Login("MyUsername","MyPassword", true));
Assert.IsTrue(Client.IsLoggedIn());

The client is an instance of the automatically generated ServiceReference client for .net. The first assertion passes but the second one fails, i.e. from one method call to the next it stops being logged in. A similar method in the silverlight application would pass.

How can I make normal .net behave correctly as silverlight would? Is there just a better way of configuring client/service for full .net?

Aditional Info Requested

Service Config:

<services>
  <service behaviorConfiguration="MyBehaviour" name="SSCCMembership.Web.Services.LoginService">
    <endpoint address="" binding="customBinding" bindingConfiguration="customBindingBinary"
      contract="SSCCMembership.Web.Services.LoginService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<bindings>
  <customBinding>
    <binding name="customBindingBinary">
      <binaryMessageEncoding />
      <httpTransport />
    </binding>
  </customBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior name="MyBehaviour">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

Authentication Config:

<authentication mode="Forms" />
<membership defaultProvider="OdbcProvider">
  <providers>
    <clear />
    <add name="OdbcProvider" type="SSCCMembership.Web.SimpleMembershipProvider" applicationName="/SSCCMembership" requiresUniqueEmail="false" connectionStringName="mainConn" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" writeExceptionsToEventLog="true" />
  </providers>
</membership>

I then use the following to construct the client in WPF

public static T LoadService<T>(string URI, Func<CustomBinding, EndpointAddress, T> F)
{
    try
    {
        Uri U = new Uri(new Uri(Root), URI);

        BinaryMessageEncodingBindingElement binary = new BinaryMessageEncodingBindingElement();
        HttpTransportBindingElement transport;
        if (U.Scheme == "http")
            transport = new HttpTransportBindingElement();
        else if (U.Scheme == "https")
            transport = new HttpsTransportBindingElement();
        else
            throw new Exception(U.Scheme + " is not a recognised URI scheme");
        transport.MaxBufferSize = int.MaxValue;
        transport.MaxReceivedMessageSize = transport.MaxBufferSize;
        transport.AllowCookies = true;

        CustomBinding binding;
        binding = new CustomBinding(binary, transport);


        EndpointAddress address = new EndpointAddress(U);

        return F(binding, address);
    }
    catch (Exception)
    {
        return default(T);
    }
}

Which I call like:

var Client = LoadService(ServiceLocation, (b,e)=>new LoginServiceClient(b,e));
ForbesLindesay
  • 10,482
  • 3
  • 47
  • 74
  • Is your binding configured to allow cookies? – RoccoC5 Sep 23 '11 at 00:05
  • @RoccoC5 My binding is created using 'new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement())' How do I set it to enable cookies? – ForbesLindesay Sep 23 '11 at 00:09
  • @RoccoC5 I've now tried `new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement(){ AllowCookies=true })` but it doesn't seem to make any difference – ForbesLindesay Sep 23 '11 at 00:14
  • can you post server and client config files? – Vitalik Sep 26 '11 at 21:04
  • For the sake of completeness, and as this is a crucial part here, could you also post your FormsAuthentication configuration (`/configuration/system.web/authentication/forms`), please? – mthierba Sep 26 '11 at 23:35
  • How are you hosting the service in the test context? I find it really difficult trying to replicate the failure scenario you're describing - whatever I've done so far, it always worked correctly (i.e., the client stayed logged in given that `AllowCookies` was set to true). – mthierba Sep 27 '11 at 19:34
  • I've got it hosted on 1and1 Windows shared hosting, I'll try it on the local dev server later, 1and1 can be a bit rubbish with some things (I'm thinking of moving it to host it on Azure) – ForbesLindesay Sep 28 '11 at 18:08

3 Answers3

1

I think the main problem you are having is due to the context that each application runs in.

A Silverlight application runs in the context of the web-page it's hosted in - and thus, can maintain session info, cookies, and all sorts of other things that you don't need to manually worry about.

As soon as you connect with an application running outside of the browser, your context (as far as asp.net is concerned) has changed. Have you tried enabling/installing the silverlight application out-of-browser to see if you have the same errors?

One way to work around this is to use the Silverlight Unit Test project and connect that to your web service for testing. (I have successfully done this with enterprise silverlight apps for the company I work for) The silverlight unit test project results in a silverlight app that can be hosted on a web page, and run from there - in the same context as any other silverlight app, as far as ASP.net is concerned, making your web-service calls much less likely to fail due to context.

Check out the Silverlight Unit Test Famework Homepage for more info...

EtherDragon
  • 2,679
  • 1
  • 18
  • 24
  • +1 It does work fine out of browser, although I suspect you're along the right lines. I've done silverlight unit testing before and it would certainly be a fallback option, I'd just like the proper integration with Visual Studio/tfs etc. – ForbesLindesay Sep 27 '11 at 15:50
  • Yea, that is one of the failings of Silverlight Test Framework, it can't be integrated into TFS. – EtherDragon Sep 27 '11 at 16:46
  • On the other hand, it was much easier to understand when I was first learning to use unit tests :) – ForbesLindesay Sep 27 '11 at 16:49
0

Change your IsLoggedIn() method to reference the ServiceSecurityContext instead of HttpContext:

[OperationContract]
public bool IsLoggedIn()
{
    return ServiceSecurityContext.Current.PrimaryIdentity.IsAuthenticated;
}
RoccoC5
  • 4,185
  • 16
  • 20
0

I had this same type of problem and ended up just implementing the WCF Authentication Services... The documentation was straight forward and it works great with the ASP.NET forms auth provider.
http://msdn.microsoft.com/en-us/library/bb386582.aspx

Nick Nieslanik
  • 4,388
  • 23
  • 21
  • For some reason, there are problems when I try using that with my web-host. At any rate, the fact that it works for silverlight means it should be possible to deal with this by just modifying the client (which is what I'd prefer) – ForbesLindesay Sep 23 '11 at 03:07