You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VS2022添加服务引用:.NET Framework项目未生成ClientCredentials

.NET Framework服务引用代理缺失ClientCredentials的解决方案

问题场景

为.NET Framework和.NET 8项目添加同一WCF服务引用,.NET 8生成的代理能正常获取ClientCredentials以设置用户名密码,但.NET Framework生成的代理类未显式暴露该属性,导致无法配置身份验证信息。

相关代码片段

WSDL安全策略

<wsp:Policy wsu:Id="WSHttpBinding_IQuery_2012_04_policy">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy>
                    <sp:TransportToken>
                        <wsp:Policy>
                            <sp:HttpsToken RequireClientCertificate="false" />
                        </wsp:Policy>
                    </sp:TransportToken>
                    <sp:AlgorithmSuite>
                        <wsp:Policy>
                            <sp:Basic256 />
                        </wsp:Policy>
                    </sp:AlgorithmSuite>
                    <sp:Layout>
                        <wsp:Policy>
                            <sp:Strict />
                        </wsp:Policy>
                    </sp:Layout>
                    <sp:IncludeTimestamp />
                </wsp:Policy>
            </sp:TransportBinding>
            <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy>
                    <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                            <sp:WssUsernameToken10 />
                        </wsp:Policy>
                    </sp:UsernameToken>
                </wsp:Policy>
            </sp:SignedSupportingTokens>
            <sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy />
            </sp:Wss11>
            <sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy>
                    <sp:MustSupportIssuedTokens />
                    <sp:RequireClientEntropy />
                    <sp:RequireServerEntropy />
                </wsp:Policy>
            </sp:Trust10>
            <wsaw:UsingAddressing />
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

生成的绑定配置

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IQuery_2012_04">
                <security mode="TransportWithMessageCredential">
                    <transport clientCredentialType="None" />
                    <message clientCredentialType="UserName" establishSecurityContext="false" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://somehost/ptsqamt/Maintain/Services/Data/2012/04/Query.svc"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IQuery_2012_04"
            contract="PTSQueryService.IQuery_2012_04" name="WSHttpBinding_IQuery_2012_04" />
    </client>
</system.serviceModel>

.NET Framework生成的代理片段

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class Query_2012_04Client : System.ServiceModel.ClientBase<WCFTest.PTSQueryService.IQuery_2012_04>, WCFTest.PTSQueryService.IQuery_2012_04 {
    
    public Query_2012_04Client() {
    }
    
    public Query_2012_04Client(string endpointConfigurationName) : 
            base(endpointConfigurationName) {
    }
    
    public Query_2012_04Client(string endpointConfigurationName, string remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }
    
    public Query_2012_04Client(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }
    
    public Query_2012_04Client(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress) {
    }
    
    public WCFTest.PTSQueryService.QueryParameter[] GetQueryParameters(int qtype, string qname) {
        return base.Channel.GetQueryParameters(qtype, qname);
    }
    
    public System.Threading.Tasks.Task<WCFTest.PTSQueryService.QueryParameter[]> GetQueryParametersAsync(int qtype, string qname) {
        return base.Channel.GetQueryParametersAsync(qtype, qname);
    }
    
    public string GetQueryData(int qtype, string qname, WCFTest.PTSQueryService.QueryArgument[] args, int page, int pageSize) {
        return base.Channel.GetQueryData(qtype, qname, args, page, pageSize);
    }
    
    public System.Threading.Tasks.Task<string> GetQueryDataAsync(int qtype, string qname, WCFTest.PTSQueryService.QueryArgument[] args, int page, int pageSize) {
        return base.Channel.GetQueryDataAsync(qtype, qname, args, page, pageSize);
    }
}

.NET 8生成的代理片段

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.2.0-preview1.23462.5")]
public partial class Query_2012_04Client : System.ServiceModel.ClientBase<PTSQueryService.IQuery_2012_04>, PTSQueryService.IQuery_2012_04
{
    
    /// <summary>
    /// Implement this partial method to configure the service endpoint.
    /// </summary>
    /// <param name="serviceEndpoint">The endpoint to configure</param>
    /// <param name="clientCredentials">The client credentials</param>
    static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
    
    public Query_2012_04Client() : 
            base(Query_2012_04Client.GetDefaultBinding(), Query_2012_04Client.GetDefaultEndpointAddress())
    {
        this.Endpoint.Name = EndpointConfiguration.WSHttpBinding_IQuery_2012_04.ToString();
        ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
    }
    
    public Query_2012_04Client(EndpointConfiguration endpointConfiguration) : 
            base(Query_2012_04Client.GetBindingForEndpoint(endpointConfiguration), Query_2012_04Client.GetEndpointAddress(endpointConfiguration))
    {
        this.Endpoint.Name = endpointConfiguration.ToString();
        ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
    }
    
    public Query_2012_04Client(EndpointConfiguration endpointConfiguration, string remoteAddress) : 
            base(Query_2012_04Client.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
    {
        this.Endpoint.Name = endpointConfiguration.ToString();
        ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
    }
    
    public Query_2012_04Client(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(Query_2012_04Client.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
    {
        this.Endpoint.Name = endpointConfiguration.ToString();
        ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
    }
    
    public Query_2012_04Client(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress)
    {
    }
    
    public System.Threading.Tasks.Task<PTSQueryService.QueryParameter[]> GetQueryParametersAsync(int qtype, string qname)
    {
        return base.Channel.GetQueryParametersAsync(qtype, qname);
    }
    
    public System.Threading.Tasks.Task<string> GetQueryDataAsync(int qtype, string qname, PTSQueryService.QueryArgument[] args, int page, int pageSize)
    {
        return base.Channel.GetQueryDataAsync(qtype, qname, args, page, pageSize);
    }
    
    public virtual System.Threading.Tasks.Task OpenAsync()
    {
        return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndOpen));
    }
    
    private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
    {
        if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_IQuery_2012_04))
        {
            System.ServiceModel.WSHttpBinding result = new System.ServiceModel.WSHttpBinding();
            result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
            result.MaxReceivedMessageSize = int.MaxValue;
            result.AllowCookies = true;
            result.Security.Mode = System.ServiceModel.SecurityMode.TransportWithMessageCredential;
            result.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.None;
            result.Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.UserName;
            result.Security.Message.EstablishSecurityContext = false;
            return result;
        }
        throw new System.InvalidOperationException(string.Format("Could not find endpoint with name '{0}'.", endpointConfiguration));
    }
    
    private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration)
    {
        if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_IQuery_2012_04))
        {
            return new System.ServiceModel.EndpointAddress("https://somehost/ptsqamt/Maintain/Services/Data/2012/04/Query.s" +
                    "vc");
        }
        throw new System.InvalidOperationException(string.Format("Could not find endpoint with name '{0}'.", endpointConfiguration));
    }
    
    private static System.ServiceModel.Channels.Binding GetDefaultBinding()
    {
        return Query_2012_04Client.GetBindingForEndpoint(EndpointConfiguration.WSHttpBinding_IQuery_2012_04);
    }
    
    private static System.ServiceModel.EndpointAddress GetDefaultEndpointAddress()
    {
        return Query_2012_04Client.GetEndpointAddress(EndpointConfiguration.WSHttpBinding_IQuery_2012_04);
    }
    
    public enum EndpointConfiguration
    {
        
        WSHttpBinding_IQuery_2012_04,
    }
}

解决方案

方法1:直接访问基类属性

.NET Framework生成的代理类继承自ClientBase<T>,基类本身包含ClientCredentials属性,无需额外修改,直接通过实例访问即可:

var client = new Query_2012_04Client();
client.ClientCredentials.UserName.UserName = "你的用户名";
client.ClientCredentials.UserName.Password = "你的密码";

// 调用服务方法
var result = client.GetQueryParameters(1, "test_query");

方法2:扩展代理类(推荐)

利用代理类的partial特性,添加扩展部分封装凭证设置逻辑,提升代码复用性:

public partial class Query_2012_04Client
{
    public void SetCredentials(string username, string password)
    {
        ClientCredentials.UserName.UserName = username;
        ClientCredentials.UserName.Password = password;
    }
}

使用时直接调用:

var client = new Query_2012_04Client();
client.SetCredentials("你的用户名", "你的密码");

方法3:重新生成代理

使用svcutil.exe命令行工具重新生成代理,确保凭证相关配置被正确识别:

svcutil.exe https://somehost/ptsqamt/Maintain/Services/Data/2012/04/Query.svc /out:QueryClient.cs /config:app.config

方法4:手动构造绑定与端点

如果自动生成的代理存在问题,可手动创建绑定和端点,直接初始化客户端:

var binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;

var endpointAddress = new EndpointAddress("https://somehost/ptsqamt/Maintain/Services/Data/2012/04/Query.svc");

var client = new Query_2012_04Client(binding, endpointAddress);
client.ClientCredentials.UserName.UserName = "你的用户名";
client.ClientCredentials.UserName.Password = "你的密码";

内容的提问来源于stack exchange,提问作者Mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:12:31