我在.NET框架中发现了一个错误,或者我做错了什么?密码在WCF中不能包含英镑?
这是故事。
我试图设置在WCF通道密码昨天那样:
channelFactory.Credentials.UserName.UserName = credentials.Username;
channelFactory.Credentials.UserName.Password = credentials.Password;
,然后调用Web服务方法,当我得到这个错误:
System.ServiceModel.CommunicationException
Message=An error (The request was aborted: The request was canceled.) occurred while transmitting data over the HTTP channel.
Source=mscorlib
StackTrace:
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
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.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at PocketKings.Tools.Services.PopulationManager.Client.PopulationService.IPopulationService.ResolvePopulationMember(ResolveRealmMemberQuery request)
InnerException: System.Net.WebException
Message=The request was aborted: The request was canceled.
Source=System
StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
InnerException: System.NotSupportedException
Message=This method is not supported by this class.
Source=System
StackTrace:
at System.Net.BasicClient.EncodingRightGetBytes(String rawString)
at System.Net.BasicClient.Lookup(HttpWebRequest httpWebRequest, ICredentials credentials)
at System.Net.BasicClient.Authenticate(String challenge, WebRequest webRequest, ICredentials credentials)
at System.Net.AuthenticationManager.Authenticate(String challenge, WebRequest request, ICredentials credentials)
at System.Net.AuthenticationState.AttemptAuthenticate(HttpWebRequest httpWebRequest, ICredentials authInfo)
at System.Net.HttpWebRequest.CheckResubmitForAuth()
at System.Net.HttpWebRequest.CheckResubmit(Exception& e)
at System.Net.HttpWebRequest.DoSubmitRequestProcessing(Exception& exception)
at System.Net.HttpWebRequest.ProcessResponse()
at System.Net.HttpWebRequest.SetResponse(CoreResponseData coreResponseData)
所以我开始寻找在它和日志显示,我甚至没有达到服务器。事实证明,引发异常的.NET框架方法(System.Net.BasicClient.EncodingRightGetBytes(String rawString))不喜欢英镑符号(£)。
我复制从反射器的方法,并写了一个快速的单元测试和英镑是,它不象所有我可以键入键盘的唯一字符:
internal static byte[] EncodingRightGetBytes(string rawString)
{
byte[] bytes = Encoding.Default.GetBytes(rawString);
string strB = Encoding.Default.GetString(bytes);
if (string.Compare(rawString, strB, StringComparison.Ordinal) != 0)
{
throw ExceptionHelper.MethodNotSupportedException;
}
return bytes;
}
这是我的单元测试,以检查这个方法:
[Test]
public void test123()
{
string domain = "localhost";
string userName = "lukk";
string charactersToCheck = @"¬`!£$%^&*()_+={}[]:;@'~#<>,.?/|\";
foreach (var character in charactersToCheck.ToCharArray())
{
string internalGetPassword = character.ToString();
try
{
// begin - this assignement was copied from System.Net.BasicClient.Lookup method
byte[] inArray = EncodingRightGetBytes(
(!string.IsNullOrEmpty(domain) ? (domain + @"\") : "")
+ userName
+ ":"
+ internalGetPassword);
//end
}
catch (Exception ex)
{
Console.WriteLine(string.Format("this character is bad: {0}", internalGetPassword));
}
}
}
正如你可以看到EncodingRightGetBytes比较两个字符串,他们是不同的,如果原始的字符串(rawString)包含英镑。当我更换
EncodingRightGetBytes工作正常...
谷歌搜索这个方法的名字带回很少环节,其中之一就是这个“Encoding.Default。”“Encoding.UTF8”: http://support.microsoft.com/kb/943511
我正在使用VS 2010与asp.net项目设置为使用.net 3.5。
那么这是.NET框架中的错误还是我做错了什么?
编辑: 当我查询在立即窗口中运行Encoding.Default我的测试,而我得到这个:
?Encoding.Default
{System.Text.SBCSCodePageEncoding}
[System.Text.SBCSCodePageEncoding]: {System.Text.SBCSCodePageEncoding}
BodyName: "iso-8859-2"
CodePage: 1250
dataItem: {System.Globalization.CodePageDataItem}
decoderFallback: {System.Text.InternalDecoderBestFitFallback}
DecoderFallback: {System.Text.InternalDecoderBestFitFallback}
EncoderFallback: {System.Text.InternalEncoderBestFitFallback}
encoderFallback: {System.Text.InternalEncoderBestFitFallback}
EncodingName: "Central European (Windows)"
HeaderName: "windows-1250"
IsBrowserDisplay: true
IsBrowserSave: true
IsMailNewsDisplay: true
IsMailNewsSave: true
IsReadOnly: true
IsSingleByte: true
m_codePage: 1250
m_deserializedFromEverett: false
m_isReadOnly: true
WebName: "windows-1250"
WindowsCodePage: 1250
假设您使用的是英式键盘,如果您输入±,§或€作为字符串的一部分(全部在英式键盘上找到)会发生什么?如果这些都失败了,那么问题肯定是7比特编码和8比特编码,因为所有这些字符都具有高于128的代码(即使用8比特),因此无法用默认编码正确处理,这很可能,是拉丁语1或其一些变体。有没有办法将编码更改为UTF8? –
这听起来像是一个问题,英镑字符被编码为'扩展'的ASCII字符,只有当您知道所使用的代码页时才会有意义(显然,密码散列不会包含用于代码页的代码页使它),所以编码方法可能会正确地拒绝含糊不清的编码字符。 UTF8听起来像是正确的解决方案。 – David
嗨,大家好,感谢您的评论。 @Aleks - 我添加了这三个字符:“±§”给我的测试字符串,他们都通过了测试。顺便说一下,我的键盘是英语(爱尔兰) – lukk