我最近使用某种网络方法遇到了很大问题:
void CheckGfiHelpdesks(string ticket, GfiCheck[] newHelpdeskChecks, GfiCheck[] otherChecks)
我用这段代码调用了这个方法:
List<GfiCheck> newFailedChecks = new List<GfiCheck>();
List<GfiCheck> otherFailedChecks = new List<GfiCheck>();
//do some work, create new GfiCheck items, fill the lists
Webclient.CheckGfiHelpdesks(Ticket, newFailedChecks.ToArray(), otherFailedChecks.ToArray());
newFailedChecks和otherFailedChecks是List。当该方法在IIS上作为SOAP服务运行时,这一直正常工作。
然而,在我将完全相同的方法复制到WCF服务之后,该调用产生了一个错误的请求&#34;异常。
最终我发现了.ToArray()确实是问题所在。这样:
Webclient.CheckGfiHelpdesks(Ticket, newFailedChecks.ToArray<GfiCheck>(), otherFailedChecks.ToArray<GfiCheck>());
即。使用System.Linq.Enumerable.ToArray<T>()
代替System.Collections.Generic.List<T>.ToArray()
最终解决了问题,异常消失了。
这种差异的解释是什么?数组是一个数组,但显然不是?
确切的例外是:
System.ServiceModel.ProtocolException
远程服务器返回了意外响应:(400)Bad Request。
堆栈跟踪:
服务器堆栈跟踪:
at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request,HttpWebResponse response,HttpChannelFactory factory,WebException responseException,ChannelBinding channelBinding)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
在System.ServiceModel.Channels.RequestChannel.Request(消息消息,TimeSpan超时)
在System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息消息,TimeSpan超时)
at System.ServiceModel.Channels.ServiceChannel.Call(String action,Boolean oneway,ProxyOperationRuntime operation,Object [] ins,Object [] outs,TimeSpan timeout)
在System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime operation)
在System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
&GT;
在[0]处重新抛出异常:
在System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData,Int32 type)
在MonitoringService.BL.CentronService.ICentronService.CheckGfiHelpdesks(String ticket,GfiCheck [] newHelpdeskChecks,GfiCheck [] otherChecks)
在C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.BL \ Service中的MonitoringService.BL.CentronService.CentronServiceClient.CheckGfiHelpdesks(String ticket,GfiCheck [] newHelpdeskChecks,GfiCheck [] otherChecks)参考文献\ CentronService \ Reference.cs:Zeile 5368。
位于C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.BL \ ConnectorBL.cs:Zeile 120中的MonitoringService.BL.ConnectorBL.CheckHelpdesks(List`1客户端)。
位于C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.Client \ MainForm.cs:Zeile 124中的MonitoringService.WinForm.MainForm.LoadChecks()。
在C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.Client \ MainForm.cs:Zeile 114中的MonitoringService.WinForm.MainForm.btnLoad_Click(Object sender,EventArgs e)中。
在System.Windows.Forms.Control.OnClick(EventArgs e)
在DevExpress.XtraEditors.BaseButton.OnClick(EventArgs e)
在DevExpress.XtraEditors.BaseButton.OnMouseUp(MouseEventArgs e)
在System.Windows.Forms.Control.WmMouseUp(消息&amp; m,MouseButtons按钮,Int32点击)
在System.Windows.Forms.Control.WndProc(Message&amp; m)
在DevExpress.Utils.Controls.ControlBase.WndProc(消息&amp; m)
at DevExpress.XtraEditors.BaseControl.WndProc(Message&amp; msg)
在System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&amp; m)
在System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&amp; m)
在System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam)
在System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG&amp; msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,Int32 reason,Int32 pvLoopData)
在System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason,ApplicationContext context)
在System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason,ApplicationContext context)
在System.Windows.Forms.Application.Run(Form mainForm)
在C:\ Users \ sohrm \ documents \ visual studio 2010 \ Projects \ MonitoringService \ MonitoringService.Client \ Program.cs:Zeile 22中的MonitoringService.WinForm.Program.Main()处。
在System.AppDomain._nExecuteAssembly(RuntimeAssembly程序集,String [] args)
在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean ignoreSyncCtx)
在System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态)
在System.Threading.ThreadHelper.ThreadStart()
答案 0 :(得分:1)
System.Collections.Generic.List<T>.ToArray()
和System.Linq.Enumerable.ToArray<T>()
之间应该没有区别。让我们看看里面发生了什么:
System.Collections.Generic.List<T>
只需创建新数组并将内部项数组复制到其中:
public T[] ToArray()
{
T[] destinationArray = new T[this._size];
Array.Copy(this._items, 0, destinationArray, 0, this._size);
return destinationArray;
}
System.Linq.Enumerable
无法访问列表的内部项数组,因此它通过缓冲区创建数组:
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw Error.ArgumentNull("source");
Buffer<TSource> buffer = new Buffer<TSource>(source);
return buffer.ToArray();
}
缓冲区内发生了什么? List<T>
为ICollection<T>
,因此只需CopyTo
调用List<T>
{/ 1>}
internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
ICollection<TElement> is2 = source as ICollection<TElement>;
length = is2.Count;
if (length > 0)
{
array = new TElement[length];
// implemented as Array.Copy(this._items, 0, array, 0, this._size);
is2.CopyTo(array, 0);
}
this.items = array;
this.count = length;
}
如您所见,项目通过列表的方法CopyTo复制到新数组,这与ToArray方法内部完全相同。但是使用System.Linq.Enumerable
你有一个小缺点 - 在将列表项复制到缓冲区后,创建另一个数组,并将缓冲区中的项复制到该数组:
internal TElement[] ToArray()
{
if (this.count == 0)
return new TElement[0];
if (this.items.Length == this.count)
return this.items;
TElement[] destinationArray = new TElement[this.count];
Array.Copy(this.items, 0, destinationArray, 0, this.count);
return destinationArray;
}
因此,在这两种情况下,列表中的项目都通过相同的方法Array.Copy
复制到新数组。但是在Enumerable
的情况下,这发生了两次。如果我处理ToArray
,我宁愿使用list List
实现。