23

I have a proxy object generated by Visual Studio (client side) named ServerClient. I am attempting to set ClientCredentials.UserName.UserName/Password before opening up a new connection using this code:

InstanceContext context = new InstanceContext(this);

m_client = new ServerClient(context);
m_client.ClientCredentials.UserName.UserName = "Sample";

As soon as the code hits the UserName line it fails with an "Object is read-only" error. I know this can happen if the connection is already open or faulted, but at this point I haven't called context.Open() yet.

I have configured the Bindings (which uses netTcpBinding) to use Message as it's security mode, and MessageClientCredentialType is set to UserName.

Any ideas?

13 Answers 13

16

I noticed that after creating an instance of the proxy class for the service, I can set the Username and Password once without errors and do a successful call to my webservice. When I then try to set the Username and Password again on the existing instance (unnecessary of course) I get the 'Object is Read-Only' error you mentioned. Setting the values once per instance lifetime worked for me.

Sign up to request clarification or add additional context in comments.

3 Comments

more appropriately, the credentials need to be set before any service method is called. attempting to set credentials after calling a method gives error - the credentials were set implicitly when you made the service call, and cannot be changed now; they are immutable.
In my case, even something as seemingly harmless as adding an event handler to the client object (and nothing else) caused the property to become read-only.
in my case it was setting the timeout client.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(Timeout). It make sense, you have already created a channel, too late the change factory config mate. (this changed between 4.5.2 and 4.7.2)
10

It appears that you can only access these properties pretty early in the instanciation cycle. If I override the constructor in the proxy class (ServerClient), I'm able to set these properties:

base.ClientCredentials.UserName.UserName = "Sample";

I'm beginning to appreciate the people who suggest not using the automatically built proxies provided by VS.

1 Comment

The only reason I use Microsoft's proxy is because it automatically generates Async methods..
9

here is the solution:

using SysSvcmod = System.ServiceModel.Description;

SysSvcmod.ClientCredentials clientCredentials = new SysSvcmod.ClientCredentials();
clientCredentials.UserName.UserName = "user_name";
clientCredentials.UserName.Password = "pass_word";

m_client.ChannelFactory.Endpoint.Behaviors.RemoveAt(1);
m_client.ChannelFactory.Endpoint.Behaviors.Add(clientCredentials);

3 Comments

what is m_client?
This solution really helped me to fix the issue! Thank you so much !.
I was having trouble with Endpoint.Behaviors, but this question put me back on track: stackoverflow.com/q/38333824/12808884
4

I have similar code that's passing UserName fine:

  FooServiceClient client = new FooServiceClient("BasicHttpBinding_IFooService");
  client.ClientCredentials.UserName.UserName = "user";
  client.ClientCredentials.UserName.Password = "password";

Try creating the proxy with binding name in app.config.

Comments

4

The correct syntax is:

// Remove the ClientCredentials behavior.
client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();

// Add a custom client credentials instance to the behaviors collection.
client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());

http://msdn.microsoft.com/en-us/library/ms730868.aspx

It worked for me.

Comments

3

I was facing same problem, my code started working when I changed my code i.e. assigning values to Client credential immediately after initializing Client object.

here is the solution ,

ProductClient Manager = new  ProductClient();    
Manager.ClientCredentials.UserName.UserName = txtUserName.Text;
Manager.ClientCredentials.UserName.Password = txtPassword.Text;

1 Comment

I moved my credential setting lines next to my client creation (as you mentioned), and my code started working.
2

This will not happen if the service reference is added through -> Add service reference ->Advanced->Add Web Reference-> Url/wsdl (local disk file).

2 Comments

I've just used your solution - it helped, but I'm wondering will it be a problem in furure when the .wsdl file will be updated by the owner of the service? Or I won't just see new methods untill I repeat Add service reference ->Advanced->Add Web Reference-> Url/wsdl (local disk file). and add a new xml file? Can some conflicts appear with the old generated code? Thanks!
U have to manually port the wsdl to the same location and update
2

I was facing this issue where I was trying to create a generic method to create a clients for different end points.

Here how I achieved this.

    public static T CreateClient<T>(string url) where T : class
    {
        EndpointAddress endPoint = new EndpointAddress(url);
        CustomBinding binding = CreateCustomBinding();

        T client = (T)Activator.CreateInstance(typeof(T), new object[] { binding, endPoint });
        SetClientCredentials(client);

        return client;
    }

    public static void SetClientCredentials(dynamic obj)
    {
        obj.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
        obj.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentials());

        obj.ClientCredentials.UserName.UserName = "UserId";
        obj.ClientCredentials.UserName.Password = "Password";
    }

Comments

0

I think your problem might be related to the use of the InstanceContext. I thought that was only needed for duplex communication channels from the server side.

I admit I'm not sure about this, but I think in this case you are telling the client to use an existing instance context so it thinks there is already a running service and will not allow changes.

What is driving the use of InstanceContext?

Comments

0

If using a duplex client, when you instantiate it the DuplexChannelFactory within the DuplexClientBase that your client is derived from is initialized with existing credentials so it can open the callback channel, which is why the credentials would be read only.

I second Mike's question and also ask why are you using NetTcpBinding if you are not going to use its inherent transport level security? Perhaps an HTTP based binding would be a better fit? That would allow you to use certificate based security which I believe can be modified after instantiation (http://msdn.microsoft.com/en-us/library/ms576164.aspx).

Comments

0

A shot in the dark but does netTcpBinding allow username and password validation? Try using application layer (SOAP) security using a http binding

Comments

0

or you could just simply check the Credentials

    if (client.ClientCredentials.ClientCertificate.Certificate == null || string.IsNullOrEmpty(client.ClientCredentials.ClientCertificate.Certificate.Thumbprint))
    {
        client.ClientCredentials.ClientCertificate.SetCertificate(
            StoreLocation.LocalMachine,
            StoreName.My,
            X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("CertificateThumbprint"));
    }

Comments

0

In .NET 4.6 I couldn't remove the credentials using Fabienne's answer. Kept getting Compiler Error CS0308 in the Remove method. What worked for me was this:

Type endpointBehaviorType = serviceClient.ClientCredentials.GetType();
serviceClient.Endpoint.EndpointBehaviors.Remove(endpointBehaviorType);

ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = userName;
clientCredentials.UserName.Password = password;

serviceClient.Endpoint.EndpointBehaviors.Add(clientCredentials);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.