我们有一个用 .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/