在WCF中设置ClientCredentials时出现“Object is read only”错误

时间:2008-10-13 20:57:31

标签: visual-studio wcf

我有一个名为ServerClient的Visual Studio(客户端)生成的代理对象。我试图在使用此代码打开新连接之前设置ClientCredentials.UserName.UserName / Password:

InstanceContext context = new InstanceContext(this);

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

一旦代码命中UserName行,它就会失败并显示“Object is read-only”错误。我知道如果连接已经打开或出现故障会发生这种情况,但此时我还没有调用context.Open()。

我已将Bindings(使用netTcpBinding)配置为使用Message作为其安全模式,而MessageClientCredentialType则设置为UserName。

有什么想法吗?

12 个答案:

答案 0 :(得分:12)

我注意到在为服务创建代理类的实例后,我可以设置一次没有错误的用户名和密码,并成功调用我的webservice。当我尝试在现有实例上再次设置用户名和密码时(当然不需要),我得到你提到的'对象是只读'错误。每个实例生命周期设置一次值对我有用。

答案 1 :(得分:8)

您似乎只能在实例化周期的早期访问这些属性。如果我覆盖代理类(ServerClient)中的构造函数,我可以设置这些属性:

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

我开始感谢那些建议不使用VS提供的自动构建代理的人。

答案 2 :(得分:5)

这是解决方案:

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 :(得分:1)

我有类似的代码传递UserName罚款:

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

尝试在app.config中使用绑定名称创建代理。

答案 4 :(得分:1)

如果通过 - >添加服务引用,则不会发生这种情况。添加服务参考 - >高级 - >添加网络参考 - > Url / wsdl(本地磁盘文件)。

答案 5 :(得分:1)

面对这个问题,我试图创建一种通用方法来为不同的端点创建客户端。

这是我实现这一目标的方式。

    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";
    }

答案 6 :(得分:0)

我认为您的问题可能与使用InstanceContext有关。我认为只需要服务器端的双工通信通道。

我承认我对此不太确定,但我认为在这种情况下,您告诉客户端使用现有的实例上下文,因此它认为已经存在正在运行的服务,并且不允许更改。

推动使用InstanceContext的原因是什么?

答案 7 :(得分:0)

如果使用双工客户端,当您实例化它时,客户端派生自的DuplexClientBase中的DuplexChannelFactory将使用现有凭据进行初始化,以便打开回调通道,这就是凭证只读的原因。

我是Mike的第二个问题,如果您不打算使用其固有的传输级安全性,还会问为什么要使用NetTcpBinding?也许基于HTTP的绑定会更合适?这将允许您使用基于证书的安全性,我认为可以在实例化后修改(http://msdn.microsoft.com/en-us/library/ms576164.aspx)。

答案 8 :(得分:0)

在黑暗中拍摄,但netTcpBinding是否允许用户名和密码验证?尝试使用http绑定

使用应用程序层(SOAP)安全性

答案 9 :(得分:0)

正确的语法是:

// 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

它对我有用。

答案 10 :(得分:0)

我遇到同样的问题,我的代码在我更改代码时开始工作,即在初始化Client对象后立即将值分配给Client凭证。

这是解决方案,

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

答案 11 :(得分:0)

或者您可以只检查凭证

    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"));
    }
相关问题