Ebbs
Ebbs

Reputation: 1050

Object values defaulting

I converted my WCF Services today to use WSHttpBinding instead of BasicHttpBinding. It is still in the development stage and thus I am using self signed certificates. The example that I followed is located Here

After finally getting the code to work like the example illustrates (follow the examples of the configs in the code that one can download), I decided to proceed to use Channel Factories like I did before.

Now when I make a call to a WCF method, I can clearly see that the object that I am sending is populated with the expected values, but if I step into the WCF side, the values are their defaults. For example Guid's will be Empty Guid's and int's will be 0. Always.

Any idea what might be causing this? here is some of my code:

In the web.config:

<add key="ClientCertificate" value="WcfClient" />
<add key="ServerCertificate" value="WcfServer" />

<system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CustomBehavior">
          <clientCredentials>
            <clientCertificate findValue="WcfClient"
                               x509FindType="FindBySubjectName"
                               storeLocation="CurrentUser"
                               storeName="My" />
            <serviceCertificate>
              <authentication certificateValidationMode="PeerTrust"/>
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IDocumentsService" closeTimeout="00:10:00"
          openTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="2147483647"
          maxReceivedMessageSize="2147483647" messageEncoding="Mtom" allowCookies="true">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
            maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="Message">
              <transport clientCredentialType="Windows" proxyCredentialType="None"
                  realm="" />
              <message clientCredentialType="Certificate" negotiateServiceCredential="true"
                  algorithmSuite="Default" establishSecurityContext="true" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:58790/DocumentsService.svc"  
                binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IDocumentsService"
                contract="DocumentsService.IDocumentsService"
                name="WSHttpBinding_IDocumentsService"
                behaviorConfiguration="CustomBehavior">
        <identity>
          <dns value="WcfServer" />
        </identity>
      </endpoint>
    </client>
</system.serviceModel>

This is my channel factory

public static class ServiceObjects
{
    public static IDocumentsService DocumentsSVC { get { return GetDocServiceClient(); } }


    #region Private Members
    private static WSHttpBinding _DMBinding = new WSHttpBinding("WSHttpBinding_IDocumentsService");
    private static EndpointIdentity _DMIdentity = EndpointIdentity.CreateDnsIdentity(ConfigurationManager.AppSettings.Get("ServerCertificate"));
    private static EndpointAddress _DMEndpoint = new EndpointAddress(new Uri(ConfigurationManager.AppSettings.Get("DocumentsService")), _DMIdentity);


    private static IDocumentsService GetDocServiceClient()
    {
        ChannelFactory<IDocumentsService> _docSvcFactory = new ChannelFactory<IDocumentsService>(_DMBinding, _DMEndpoint);

        _docSvcFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;

        _docSvcFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, ConfigurationManager.AppSettings.Get("ClientCertificate"));
        _docSvcFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, ConfigurationManager.AppSettings.Get("ServerCertificate"));


        return _docSvcFactory.CreateChannel();
    }
    #endregion
}

When I call the service, on the Client side for example:

private static Guid _UserID = (HttpContext.Current.User as Titan.Web.Classes.Identity.CustomPrincipal).UserId;

ServiceObjects.DocumentsSVC.GetDocumentsByFolderID(new DocumentRequest { CurrentUserID = _UserID })

I can see _UserID is populated, but on the server side it's not.

This is in my service's config

<system.serviceModel>
<bindings>
  <wsHttpBinding>
    <binding name="wsHttpEndpointBinding" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="true" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Mtom">
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
      <security>
        <message clientCredentialType="Certificate" />
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<services>
  <service name="Titan.WCF.Documents.DocumentsService" behaviorConfiguration="DocumentsServiceBehavior">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="Titan.WCF.Documents.IDocumentsService">
      <!-- 
          Upon deployment, the following identity element should be removed or replaced to reflect the 
          identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
          automatically.
      -->
      <identity>
        <dns value="localhost"/>
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="DocumentsServiceBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
      <dataContractSerializer maxItemsInObjectGraph="2147483647" />
      <serviceCredentials>
        <clientCertificate>
          <!-- Remove the NoCheck in production, this is only for when we use a self signed cert -->
          <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
        </clientCertificate>
        <serviceCertificate findValue="WCfServer"
          storeLocation="CurrentUser"
          storeName="My"
          x509FindType="FindBySubjectName" />
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
</system.serviceModel>

Upvotes: 0

Views: 161

Answers (3)

dhrumilap
dhrumilap

Reputation: 142

Of course, since you've changed your configuration in the service you need to update the service reference so that the client too can update its configuration on its side. Unless you do that the client will keep calling the service with old configuration which it reads from its config file while the service runs with the new configuration settings.

It may be tiring, but it's the way it is.

Upvotes: 1

Ebbs
Ebbs

Reputation: 1050

I am not sure why this would make a difference, but it did.

I needed to update my service references.

A rookie mistake I guess, but why would that make a difference if the only thing I did was to change the bindings, endpoints etc?

Upvotes: 0

dhrumilap
dhrumilap

Reputation: 142

It seems the issue lies in the way you make a call to the service using the following code:

ServiceObjects.DocumentsSVC.GetDocumentsByFolderID(new DocumentRequest { CurrentUserID = _UserID });

Here you are trying to invoke the service function without creating a proxy object of the service. And that is because you have written a static class in the service.

In a WCF service you can't use static classes. You need to create an instance of the class (service proxy object) and then invoke the service function.

Upvotes: 0

Related Questions