Getting “Object is read only” error when setting C

2020-06-08 01:40发布

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?

12条回答
放我归山
2楼-- · 2020-06-08 02:04

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?

查看更多
欢心
3楼-- · 2020-06-08 02:04

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).

查看更多
Bombasti
4楼-- · 2020-06-08 02:07

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.

查看更多
兄弟一词,经得起流年.
5楼-- · 2020-06-08 02:07

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.

查看更多
狗以群分
6楼-- · 2020-06-08 02:08

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";
    }
查看更多
The star\"
7楼-- · 2020-06-08 02:08

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"));
    }
查看更多
登录 后发表回答