从存储过程中获取XML

时间:2016-04-13 15:50:28

标签: c# asp.net sql-server xml

我从存储过程中获取XML输出。我想要做的是获取XML并通过ASP.NET传递出来:

UnitOfWork

但我一直收到这些错误:

public XmlDocument GetPunchListXml(string communityDesc)
{
    try
    {
        using (connection = new SqlConnection(connectionString))
        {
             connection.Open();

             using (SqlCommand command = new SqlCommand("GetPunchList", connection))
             {
                   command.CommandType = CommandType.StoredProcedure;

                   SqlParameter parameter1 = new SqlParameter("@communityDesc", SqlDbType.VarChar);
                   parameter1.Value = communityDesc;
                   parameter1.Direction = ParameterDirection.Input;
                   command.Parameters.Add(parameter1);

                   var doc = new XmlDocument();
                   var reader = command.ExecuteXmlReader();
                   if (reader.Read())
                   {
                       doc.Load(reader);
                   }

                   return doc;
               }
           }
      }
      finally
      {
         connection.Close();
      }
}

我做错了什么?我试图获取XML的方式是否有问题,或者是XML本身的问题?

我尝试了以下内容:

<Error>
    <Message>An error has occurred.</Message>
    <ExceptionMessage>
        The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
    </ExceptionMessage>
    <ExceptionType>System.InvalidOperationException</ExceptionType>
    <StackTrace/>
    <InnerException>
        <Message>An error has occurred.</Message>
        <ExceptionMessage>
            Type 'System.Xml.XmlDocument' is an invalid collection type since it does not have a valid Add method with parameter of type 'System.Object'.
        </ExceptionMessage>
        <ExceptionType>
            System.Runtime.Serialization.InvalidDataContractException
        </ExceptionType>
        <StackTrace>
            at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
            at WriteArrayOfanyTypeToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
            at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
            at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
            at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
            at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
            at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph)
            at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)
            at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
                --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
            at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
        </StackTrace>
    </InnerException>
</Error>

并且遇到了这些错误:

var doc = new XmlDocument();
string s = "";
using (XmlReader reader = command.ExecuteXmlReader())
{
    while (reader.Read())
    {
        //doc.Load(reader);
        s = reader.ReadOuterXml();
        doc.LoadXml(s);
    }
}
return doc;

4 个答案:

答案 0 :(得分:7)

问题可能在于您使用XmlDocument的结果,因为我也找不到代码的任何问题。至于为什么我相信这个

  1. 您的堆栈跟踪都没有显示对您发布的代码的任何调用。他们实际上指的是HttpControllerHandler开始的例外情况,因此可能与您提供回复的位置或方式有关。
  2. 根据文档,调用SqlCommand.ExecuteXmlReader可以抛出InvalidOperationException,但它会认为这只会在The SqlConnection closed or dropped during a streaming operation. For more information about streaming, see SqlClient Streaming Support.
  3. 时发生
  4. 根据文档,调用XmlDocument.Load仅抛出异常XmlException,因此根据您收到的异常情况,这不是一个可能的失败点。
  5. 在Google上搜索异常消息后,由于Web API配置问题,我发现previous users had experienced this error,所以再次与数据库中的Xml加载无关。
  6. 对解决方案的猜测

    这是猜测,因为我不知道您正在使用什么框架,或者这是WebApi方法还是在调用堆栈中向下提供结果的方法。

    因此,您需要解决的问题是将数据转换为可以通过您使用的任何框架进行序列化的格式。如需更多帮助,请提供。

    1. 您使用的是什么框架(web api,mvc controller,asp.net,还有其他东西)
    2. 如果是网络Api - 正在调用提供数据的方法终点。如果这是该方法,则错误是您尝试直接返回XmlDocument。
      • 确保在WebApiConfig.cs文件中配置了正确的格式化程序。 GlobalConfiguration.Configuration.Formatters.Add(new System.Net.Http.Formatting.XmlMediaTypeFormatter()); GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
      • 请参阅this previous SO answer,了解如何更改方法。
      • 我建议保持原样并将其标记为私有,然后添加调用此方法的Api方法,并将结果格式化为可以传递回客户端的内容。
    3. Web Api修复

      我可以通过在Web API控制器中返回XmlDocument作为响应来复制确切的错误和消息。然后再次说明它与方法的内容无关,但更多的是响应中使用的XmlDocument。如果您直接在响应中返回XmlDocument(因此不是较大对象的一部分),我可以通过添加一个知道如何反序列化(提取实际Xml内容)的新HttpContent类型来修复它{ {1}}。这是基于XmlDocument发布的上一个SO answer。这是一个完整的自包含示例中的修复。

      Darrel Miller

      常规代码修复

      您的方法确实存在一些问题,因为它与using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using System.Web.Http; using System.Xml; namespace WebApiTests.Controllers { public class HomeController : ApiController { const string sampleData = "<?xml version=\"1.0\"?><catalog><book id=\"bk101\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre><price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description></book></catalog>"; public HttpResponseMessage Get() { var doc = new XmlDocument(); doc.LoadXml(sampleData); return new HttpResponseMessage() { RequestMessage = Request, Content = new XmlContent(doc) }; } } public class XmlContent : HttpContent { private readonly MemoryStream _Stream = new MemoryStream(); public XmlContent(XmlDocument document) { document.Save(_Stream); _Stream.Position = 0; Headers.ContentType = new MediaTypeHeaderValue("application/xml"); } protected override Task SerializeToStreamAsync(Stream stream, System.Net.TransportContext context) { _Stream.CopyTo(stream); var tcs = new TaskCompletionSource<object>(); tcs.SetResult(null); return tcs.Task; } protected override bool TryComputeLength(out long length) { length = _Stream.Length; return true; } protected override void Dispose(bool disposing) { if(_Stream != null) _Stream.Dispose(); } } } 有关。以下是带有解释的清理代码。

      SqlConnection

答案 1 :(得分:0)

更改以下代码,

var doc = new XmlDocument();
var reader = command.ExecuteXmlReader();
if (reader.Read())
{
   doc.Load(reader);
}

如下所示,

XmlDocument doc = new XmlDocument();
XmlReader reader = command.ExecuteXmlReader();
if (reader.Read())
{
    doc.Load(reader);
}

如果仍然无效,请分享您从SP返回的xml。

答案 2 :(得分:0)

XmlDocument不可序列化,而是返回XML的字符串表示

using (var stringWriter = new StringWriter())
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
    xmlDoc.WriteTo(xmlTextWriter);
    xmlTextWriter.Flush();
    return stringWriter.GetStringBuilder().ToString();
}

答案 3 :(得分:0)

您可以在MediaTypeFormatter中创建自己的简单ASP.NET Web API,直接将XmlDocument流式传输到回复。本回答的最后是一个示例实现。

使用VS向导创建新项目时,在自动生成的public static void Register(HttpConfiguration config)类的WebApiConfig方法中注册它。

// This custom media type converter must be inserted before the default media type converter that handles application/xml, do not use config.Formatters.Add(...
config.Formatters.Insert(0, new MediaTypeFormatters.XmlDocumentMediaTypeFormatter());

在控制器类方法中执行与此类似的操作

private HttpResponseMessage Get()
{
    XmlDocument doc = new XmlDocument();
    XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
    doc.AppendChild(dec);
    XmlElement rootElement = doc.CreateElement("user");
    doc.AppendChild(rootElement);
    rootElement.SetAttribute("id", "1");

    var response = Request.CreateResponse(HttpStatusCode.OK, doc, "application/xml");
    return (response);
}

自定义MediaTypeFormatter示例,以将XmlDocument流式传输到响应。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Net;
using System.Xml;

namespace Take5.MediaTypeFormatters
{
    public class XmlDocumentMediaTypeFormatter : MediaTypeFormatter
    {
        private static Type _supportedType = typeof(XmlDocument);

        public XmlDocumentMediaTypeFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
        }

        public override bool CanReadType(Type type)
        {
            return type == _supportedType;
        }

        public override bool CanWriteType(Type type)
        {
            return type == _supportedType;
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            var taskSource = new TaskCompletionSource<object>();
            try
            {
                System.Diagnostics.Debug.Assert(false, "Not fully implemented, get doc to read from readStream.");
                var doc = new XmlDocument();
                taskSource.SetResult(doc);
            }
            catch (Exception e)
            {
                taskSource.SetException(e);
            }
            return taskSource.Task;
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            var taskSource = new TaskCompletionSource<object>();
            try
            {
                XmlDocument doc = (XmlDocument)value;
                XmlWriter writer = XmlWriter.Create(writeStream, new XmlWriterSettings() { Indent = true });
                doc.WriteContentTo(writer);
                writer.Flush();

                taskSource.SetResult(null);
            }
            catch (Exception e)
            {
                taskSource.SetException(e);
            }
            return taskSource.Task;
        }
    }
}