c# - 用户代理在 .NET Core 中的 header 格式不正确

标签 c# wcf .net-core

我们有一个用 .NET Standard 2.0 编译的库,它具有 WCF 服务。为了向 Web 服务的请求添加自定义 header ,我们在此处实现了代码:https://blogs.msdn.microsoft.com/mohamedg/2012/12/13/adding-http-headers-to-wcf-calls/

当我们在 .NET Framework 应用程序中引用此库时,我们可以对所需的 Web 服务进行任何调用,并且可以正常返回正确的结果。但是,在 .NET Core 2.0 应用程序中,库经常(但并非总是!)抛出 System.FormatException,具体取决于我们设置的用户代理。

诸如“Mozilla/4.0”之类的内容不会引发错误,但“Mozilla/4.0(兼容;MSIE 6.0;MS Web Services Client Protocol 4.0.30319.42000)”会引发错误,但仅核心应用程序显示错误消息“值的格式‘(兼容;MSIE 6.0;MS Web 服务客户端协议(protocol) 4.0.30319.42000)’无效。”。

简而言之,这是代码(省略了接口(interface)中没有实现的方法)。当前的用户代理被硬编码只是为了故障排除。

internal class ClientUserAgentMessage : IClientMessageInspector
{
    public ClientUserAgentMessage(string userAgent) { }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        HttpRequestMessageProperty property = new HttpRequestMessageProperty();

        //This is an example user agent that fails, and we would not expect it to.
        property.Headers["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.42000)";
        request.Properties.Add(HttpRequestMessageProperty.Name, property);

        return null;
    }
}

internal class UserAgentEndpointBehavior : IEndpointBehavior
{
    public UserAgentEndpointBehavior() { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new ClientUserAgentMessage());
    }
}

上面的代码是在引用标准 dll 的应用程序中实现的,如下所示(省略客户端初始化详细信息):

//SoapClient and related WCF code is generated from the web service via svcutil.exe
SoapClient client = new SoapClient(...);
client.Endpoint.EndpointBehaviors.Add(new UserAgentEndpointBehavior());

//Call some web service functions...
//This succeeds in a .NET 4.7 app, 
//but blows up in a .NET Core 2.0 app due to the user agent being an "invalid format".
//client.Login();

当用户代理实际上看起来是有效格式时,为什么这只是 .NET Core 的问题?它似乎提示哪里有超过 1/、括号、冒号、分号、空格...基本上除了第一个/、下划线和小数之外的任何非字母数字。

根据要求,完整的堆栈跟踪:

   at System.Net.Http.Headers.HttpHeaderParser.ParseValue(String value, Object storeValue, Int32& index)
   at System.Net.Http.Headers.ProductInfoHeaderValue.Parse(String input)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.PrepareMessageHeaders(Message message)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.<SendRequestAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.ServiceModel.Channels.RequestChannel.<RequestAsync>d__33.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.ServiceModel.Channels.RequestChannel.<RequestAsyncInternal>d__32.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.TaskHelpers.WaitForCompletionNoSpin[TResult](Task`1 task)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)
   at generatedProxy_1.Login(LoginRequest )
   at MyServiceNamespace.SoapClient.ServiceNamespace.Soap.Login(LoginRequest request)
   at MyServiceNamespace.SoapClient.Login(String strUser, String strPass, String strKey)
   at MyLibraryNamespace.MyClass.Login(String sUser, String sPass, String sKey)  

FWIW,您可以设置为“User-Agent”以外的 header ,一切都很好(或者至少,我尝试使用“XTESTX”,没有异常(exception))。

最佳答案

我打开了一个issue 2018 年 3 月 14 日在 GitHub 上发布。

看起来这个问题已在 5 月份通过此 pull request 得到解决和修复。并且应该不再是一个问题。

关于c# - 用户代理在 .NET Core 中的 header 格式不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49262393/

相关文章:

c# - 如何使用 IEnumerable 结果正确集成测试 Web Api Controller ?

c# - 在 Task.Run 中使用 CancellationToken 超时不起作用

C# 转换为与 List 和 GroupBy 接口(interface)

c# - 自承载 WCF 服务使用 HTTP 而不是 HTTPS

c# - WCF4 (.NET Framework 4) 是否支持客户端连接池?

c# - 如何在C#中使用函数存储字符串

c# - 确保服务连通性

c# - 如何在 .Net Core 中使用 WebClient?

.net-core - appium-dotnet-driver 支持 .net core 2.x 吗?

.net - HttpClient 在高负载下不执行