Ошибка получения объекта только для чтения при настройке ClientCredentials в WCF

У меня есть прокси-объект, сгенерированный Visual Studio (на стороне клиента) с именем ServerClient. Я пытаюсь установить ClientCredentials.UserName.UserName/Password, прежде чем открывать новое соединение, используя этот код:

InstanceContext context = new InstanceContext(this);

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

Как только код попадает в строку UserName, происходит сбой с ошибкой «Объект доступен только для чтения». Я знаю, что это может произойти, если соединение уже открыто или повреждено, но на данный момент я еще не вызывал context.Open().

Я настроил Bindings (которые используют netTcpBinding) для использования Message в качестве режима безопасности, а для MessageClientCredentialType установлено значение UserName.

Есть идеи?


person Paul Mrozowski    schedule 13.10.2008    source источник


Ответы (12)


Я заметил, что после создания экземпляра прокси-класса для службы я могу один раз установить имя пользователя и пароль без ошибок и выполнить успешный вызов своего веб-сервиса. Когда я затем пытаюсь снова установить имя пользователя и пароль для существующего экземпляра (конечно, ненужного), я получаю упомянутую вами ошибку «Объект только для чтения». Установка значений один раз за время жизни экземпляра сработала для меня.

person Gerhard    schedule 02.11.2012
comment
точнее, учетные данные должны быть установлены до вызова любого метода службы. попытка установить учетные данные после вызова метода приводит к ошибке — учетные данные были заданы неявно при вызове службы и не могут быть изменены сейчас; они неизменны. - person morpheus; 08.03.2013
comment
В моем случае даже такая, казалось бы, безобидная вещь, как добавление обработчика событий к объекту клиента (и ничего больше), приводила к тому, что свойство становилось доступным только для чтения. - person nuzzolilo; 12.07.2014
comment
в моем случае он устанавливал тайм-аут client.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(Timeout). Логично, вы уже создали канал, слишком поздно менять заводской конфиг матом. (это изменилось между 4.5.2 и 4.7.2) - person Luizgrs; 15.07.2021

Похоже, что вы можете получить доступ к этим свойствам довольно рано в цикле инстанцирования. Если я переопределяю конструктор в прокси-классе (ServerClient), я могу установить эти свойства:

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

Я начинаю ценить людей, которые предлагают не использовать автоматически созданные прокси, предоставляемые VS.

person Paul Mrozowski    schedule 14.10.2008
comment
Единственная причина, по которой я использую прокси Microsoft, заключается в том, что он автоматически генерирует асинхронные методы. - person Shahin Dohan; 29.03.2017

вот решение:

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);
person Community    schedule 29.06.2009
comment
что такое м_клиент? - person Blue Clouds; 03.04.2018
comment
Это решение действительно помогло мне решить проблему! Большое спасибо !. - person Mirzan; 21.09.2020

У меня есть аналогичный код, который проходит UserName нормально:

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

Попробуйте создать прокси с именем привязки в app.config.

person Eugene Yokota    schedule 28.04.2009

Я столкнулся с той же проблемой, мой код начал работать, когда я изменил свой код, то есть присвоил значения учетным данным клиента сразу после инициализации объекта клиента.

вот решение,

ProductClient Manager = new  ProductClient();    
Manager.ClientCredentials.UserName.UserName = txtUserName.Text;
Manager.ClientCredentials.UserName.Password = txtPassword.Text;
person savitha    schedule 03.02.2015
comment
Я переместил свои строки настроек учетных данных рядом с созданием моего клиента (как вы упомянули), и мой код начал работать. - person Aaron C; 15.11.2019

Правильный синтаксис:

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

Это сработало для меня.

person Fabienne Bonzon    schedule 24.10.2013

Этого не произойдет, если ссылка на службу добавлена ​​через -> Добавить ссылку на службу -> Дополнительно-> Добавить веб-ссылку-> Url/wsdl (файл на локальном диске).

person Blue Clouds    schedule 04.04.2018
comment
Я только что использовал ваше решение - оно помогло, но мне интересно, не будет ли это проблемой в будущем, когда файл .wsdl будет обновлен владельцем службы? Или я просто не увижу новые методы, пока не повторю Добавить ссылку на службу ->Дополнительно->Добавить веб-ссылку-> Url/wsdl (файл на локальном диске) и добавлю новый файл xml? Могут ли возникнуть конфликты со старым сгенерированным кодом? Спасибо! - person Dmitriy Klyushin; 03.12.2018
comment
Вам нужно вручную перенести wsdl в то же место и обновить - person Blue Clouds; 03.12.2018

Я столкнулся с этой проблемой, когда пытался создать общий метод для создания клиентов для разных конечных точек.

Вот как я этого добился.

    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";
    }
person Atul    schedule 11.10.2018

Я думаю, что ваша проблема может быть связана с использованием InstanceContext. Я думал, что это нужно только для дуплексных каналов связи со стороны сервера.

Я признаю, что не уверен в этом, но я думаю, что в этом случае вы говорите клиенту использовать существующий контекст экземпляра, поэтому он думает, что уже запущена служба, и не допустит изменений.

Что движет использованием InstanceContext?

person Mike Two    schedule 14.10.2008

При использовании дуплексного клиента, когда вы создаете его экземпляр, DuplexChannelFactory в DuplexClientBase, производным от которого является ваш клиент, инициализируется существующими учетными данными, чтобы он мог открыть канал обратного вызова, поэтому учетные данные будут доступны только для чтения.

Я поддерживаю вопрос Майка, а также спрашиваю, почему вы используете NetTcpBinding, если вы не собираетесь использовать присущую ему безопасность на транспортном уровне? Возможно, лучше подойдет привязка на основе HTTP? Это позволит вам использовать безопасность на основе сертификатов, которую, я считаю, можно изменить после создания экземпляра (http://msdn.microsoft.com/en-us/library/ms576164.aspx).

person Kwal    schedule 30.12.2009

Выстрел в темноте, но разрешает ли netTcpBinding проверку имени пользователя и пароля? Попробуйте использовать безопасность прикладного уровня (SOAP) с помощью привязки http

person Shane    schedule 12.04.2010

или вы можете просто проверить учетные данные

    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"));
    }
person Davit Mikuchadze    schedule 25.10.2019