views:

1059

answers:

2

Hey all,

I'm at my wits end on this one. I occasionally get the error above from my .Net 2.0 asmx web service. I've got the proper XmlInclude() in place, and it only appears sometimes - when I rebuild and update the site, it may show up, it may not, no rhyme or reason. If I move some of the XmlIncludes() around, rebuild, and push the changes up, the error usually goes away.

Prior to having the build process in place that converts everything to a DLL, I was using the good ol xcopy deployment method. The error happened then, too, but then all I had to do was add a space to the file that defined all the XmlInclude() calls, and IIS would recompile and the error would go away.

For what its worth, there are a LOT of XmlIncludes defined, about 100 or so.

Any ideas?

Here's a snippet:

namespace Courses{

    [Serializable]
    [XmlInclude(typeof(UserToCourse)),
    XmlInclude(typeof(UserToCourseCollection)),        
    // ...lots more....
    XmlInclude(typeof(ReadOnlySearchResultsRecordset<UserToCourse, UserToCourseCollection>)),
    XmlInclude(typeof(AllCoursesByTrainingProgramCollection)), 
    XmlInclude(typeof(StartupObject))]
    public partial class ServiceCallResult{
       //..snipped class def
    }
}

Edit: It appears that rearranging the XmlIncludes makes the error go away, but it may or may not come back the next time I recompile and redeploy.

Edit #2: OK, some more details. Forcing a recycle by changing the web.config doesn't solve the issue, nor does completely restarting IIS. For some reason, my log didn't write out properly, so I don't have the stack trace yet.

This time, the error was occurring for 2 specific methods. I made a change to the global.asax (to attempt to fix my stack trace logging), rebuilt and updated, and one of the two methods started working. I then split the class with the XmlIncludes on it into 2 partial classes, rebuilt, updated, and both methods started working again. I'm not sure if this is a permanent fix or not at this moment, because it's so random; I'll update on the next build cycle again.

Edit #3: Definitely not a permanent fix, and I'm still not hooked into the right place to catch a full stack trace (although my other logs are all working fine). Ugh. I'll update again next round.

Edit #4: Finally have a stack trace. It doesn't catch in Visual Studio, nor in the global exception handler in my global.asax. Here are the results as displayed when invoking the method directly from the web browser:

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type System.String[] may not be used in this context.
   at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write119_ServiceCallResult(String n, String ns, ServiceCallResult o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write397_ServiceCallResult(Object o)
   at Microsoft.Xml.Serialization.GeneratedAssembly.ServiceCallResultSerializer277.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o)
   at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
   at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()

Edit #5:

This may be a symptom of the above error, so I'm not convinced it's relevant, but I'll post it anyway. If I attach to the Managed Debug Assistants and refresh a bunch, I eventually get:

Managed Debugging Assistant 'StreamWriterBufferedDataLost' has detected a problem in 'C:\Program Files\Common Files\Microsoft Shared\DevServer\9.0\WebDev.WebServer.EXE'.
Additional Information: A StreamWriter was not closed and all buffered data within that StreamWriter was not flushed to the underlying stream.  (This was detected when the StreamWriter was finalized with data in its buffer.)  A portion of the data was lost.  Consider one of calling Close(), Flush(), setting the StreamWriter's AutoFlush property to true, or allocating the StreamWriter with a "using" statement.  Stream type: System.Web.HttpResponseStream
File name: <unknown>
Allocated from:
   at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   at System.IO.StreamWriter.Init(Stream stream, Encoding encoding, Int32 bufferSize)
   at System.IO.StreamWriter..ctor(Stream stream, Encoding encoding, Int32 bufferSize)
   at System.IO.StreamWriter..ctor(Stream stream, Encoding encoding)
   at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
   at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()
   at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
   at System.Web.Services.Protocols.SyncSessionlessHandler.ProcessRequest(HttpContext context)
   at System.Web.Script.Services.ScriptHandlerFactory.HandlerWrapper.ProcessRequest(HttpContext context)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
   at System.Web.HttpApplication.ApplicationStepManager.ResumeSteps(Exception error)
   at System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
   at System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)
   at System.Web.HttpRuntime.ProcessRequestNoDemand(HttpWorkerRequest wr)
   at System.Web.HttpRuntime.ProcessRequest(HttpWorkerRequest wr)
   at Microsoft.VisualStudio.WebHost.Request.Process()
   at Microsoft.VisualStudio.WebHost.Host.ProcessRequest(Connection conn)

I'm not sure it's related...could be just the error stream.

Edit #6:

OK, more info. I've used Scott Hanselman's blog post here to step into the generated assembly. It turns out that despite the XmlInclude, the generated assembly DOES NOT have a reference to the type in it, so this is definitely a bug in .NET. I'm attempting to track down what triggers it, but something in whatever generates the output assemblies (sgen?) is failing.

Edit #7:

FYI for anyone following this, I've submitted a bug report to MS:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=523253

+1  A: 

My best guess (and it is a guess) is that touching the file is a red herring. I think it more likely that any recompilation will clear this up. For example, you could touch the web.config to force a recycle to prove or disprove my assumption when this happens.

The reason I suspect this is that the error you are receiving relates to a serialization problem. The XML Serializer is confused into thinking it cannot serialize one of your types. Because you've ruled out a lot of the common suspects such as object arrays or inclusion of other types that are inherently not serializable, I suspect a compliation race condition such as a circular reference between two of your assemblies is to blame. This particular case would be cleared up by a second compilation.

Note: A good tool to detect circular references is NDepend.

If it is not a circular reference, are you doing any code gen, using any build providers or using reflection to load any assemblies in your app or anything else that might be even slightly exotic?

Edit:

Based on your comment, you are not doing anything exotic. So, please check for circular references and (just thought of this) conflicting dependencies between your assemblies. For example, SubSonic references a number of assemblies, and if you reference one of these assemblies of a different version, it could explain how it works once and fails another time with the same code.

Jerry Bullard
Hey Jerry, the code was originally generated (no build providers, just straight up generated by a custom SubSonic template), but the generation hasn't been performed in months (no changes to the data structures). No reflection to load assemblies is taking place either. I like the idea of the web.config recycle to confirm/deny what's going on - I'll give that a shot next time this shows up.
jvenema
OK, that helps narrow down the problem. I updated my answer. Thanks.
Jerry Bullard
OK, one more update; the web.config recycle doesn't fix the issue. I've also updated the main post again...some more strangeness.
jvenema
Is the web service hosted in a web site (not a web application project)?
Jerry Bullard
Also, I haven't seen you rule out the circular references or conflicting assembly problems. Do you get any warnings when you do a full rebuild all in Visual Studio?I'm still leaning toward some kind of build order race condition. That is the only thing I can think of that could give this kind of random behavior.Is there anything in the event log at all that could offer a hint?
Jerry Bullard
Nothing I'm seeing in Visual Studio, I compile with warnings as errors. I'll double check the event log when I get the stack trace next time, didn't notice anything before.
jvenema
Jerry, what's your suggested route for checking conflicting assemblies? I've been chatting with the guys from MS, and they think that may still be the problem.
jvenema
The tool I mentioned above called NDepend should do the trick. Here are two articles on the topic:http://codebetter.com/blogs/patricksmacchia/archive/2008/09/09/interactive-code-dependencies-graph.aspx--and--http://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies
Jerry Bullard
A: 

OK, I've got a solution that works, although I'm still not sure why. This is definitely a bug in the generated proxy assembly. I found that the generated assembly sometimes just misses some of the types included in the XmlIncludes. Oddly, it seemed to be certain types specifically, though I can't find a pattern to why those ones and not others.

The solution was to create a partial class definition (it's even in the same file!) that had the XmlIncludes for only those particular types that were consistently causing problems. Since then, I haven't seen the error at all.

Definitely a bug somewhere in the generator, although what's triggering it I don't know. Hopefully this'll help someone else down the road though.

EDIT I belive I've confirmed what caused the problem. I had a reference to SharpZipLib, built for the .NET framework v1.1, in my .NET 2.0 project. When I built the app_code.dll, it added a reference to mscorlib 1.0.5. Apparently, having this additional reference was enough to cause sgen to improperly generate the temporary DLLs used when invoking the web service. So, if you have the problem...load up all referenced assemblies in ILDASM, double click the manifest, and confirm that none of them reference .NET 1.1. If they do...you're hosed.

Apparently, this did not actually fix it, as the issue is still in place, just with a different type failing.

jvenema
Congratulations for finding the problem. Please be sure to update the Connect bug report.
John Saunders
I was in contact w/ the guy off-list, but I've updated the Connect report as well - good call.
jvenema
Ugh. Fail. It's still there, despite my nice clean dll.
jvenema