如何使用 HttpWebRequest 将数据发布到 MVC 控制器?

Posted

技术标签:

【中文标题】如何使用 HttpWebRequest 将数据发布到 MVC 控制器?【英文标题】:How do I post data to MVC Controller using HttpWebRequest? 【发布时间】:2011-09-10 09:05:13 【问题描述】:

我正在尝试将数据发布到 MVC 控制器操作,但到目前为止还没有成功。

这是帖子数据的结构:

private string makeHttpPostString(XmlDocument interchangeFile)
    
        string postDataString = "uid=0&localization=1&label=2&interchangeDocument=3";

        InterchangeDocument interchangeDocument =  new InterchangeDocument(interchangeFile);
        using (var stringWriter = new StringWriter())
        using (var xmlTextWriter = XmlWriter.Create(stringWriter))
        
            interchangeFile.WriteTo(xmlTextWriter);
            string interchangeXml = HttpUtility.UrlEncode(stringWriter.GetStringBuilder().ToString());
            string hwid = interchangeDocument.DocumentKey.Hwid;
            string localization = interchangeDocument.DocumentKey.Localization.ToString();
            string label = ConfigurationManager.AppSettings["PreviewLabel"];

            return (string.Format(postDataString, hwid, localization, label, interchangeXml));
        

    

这是请求:

 HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(controllerUrl);

        webRequest.Method = "POST";
      //  webRequest.ContentType = "application/x-www-form-urlencoded";

        string postData = makeHttpPostString(interchangeFile);
        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        webRequest.ContentLength = byteArray.Length;

        using (Stream dataStream = webRequest.GetRequestStream())
        
            dataStream.Write(byteArray, 0, byteArray.Length);
        

        HttpWebResponse webresponse = (HttpWebResponse) webRequest.GetResponse();

当我将请求的内容类型设置为“application/x-www-form-urlencoded”时,GetReponse() 失败并显示服务器错误代码 500。当我将其注释掉并且仅对 xml 数据“interchangeXml”进行 httpencode 时, post 已发送,但只有第三个参数“label”到达控制器。其他为空。

当这些值之一是 xml 数据时,将值发布到控制器操作的正确方法是什么?

谢谢!

更新

我通过查询字符串发送除了 XML 之外的所有参数。但是,现在的问题是我不知道如何访问控制器操作中发布的数据。有人可以告诉我如何使用控制器操作从 HttpRequest 访问 xml 吗?

更新

我已经重构了上面的代码以使用 Darin 给我的建议。我使用 WebClient UploadValues() 收到内部服务器错误 (500)。

行动:

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult BuildPreview(PreviewViewModel model)
        
            ...
        

请求:

private string PostToSxController(XmlDocument interchangeFile, string controllerUrl)
        
            var xmlInterchange = new InterchangeDocument(interchangeFile);
            using (var client = new WebClient())
            
                var values = new NameValueCollection()
                                 
                                     "uid", xmlInterchange.DocumentKey.Hwid,
                                     "localization", xmlInterchange.DocumentKey.Localization.ToString(),
                                     "label", ConfigurationManager.AppSettings["PreviewLabel"],
                                     "interchangeDocument", interchangeFile.OuterXml 
                                 ;

                 byte[] result = null;

                try
                
                    result = client.UploadValues(controllerUrl, values);
                
                catch(WebException ex)
                
                    var errorResponse = ex.Response;
                    var errorMessage = ex.Message;
                

                Encoding encoding = Encoding.UTF8;
               return encoding.GetString(result);


            
        

路线:

routes.MapRoute(
                "BuildPreview",
                "SymptomTopics/BuildPreview/model",
                new  controller = "SymptomTopics", action = "BuildPreview", model = UrlParameter.Optional  
            );

【问题讨论】:

您的 MVC 操作期望的数据结构是什么?你能不能只在 xml 中发布所有数据,而不是查询字符串? 控制器操作需要 4 个字符串:interchangeXml、hwid、本地化和标签。不.. xml 不会也不会包含我尝试发布的其他值。 您是否尝试过使用 Fiddler 或 Firebug 之类的工具来准确查看您的客户端向服务器发送的内容?它可能无法正确输出。 我正在使用 c# 从 thik 客户端发出 httprequest。该请求不是来自浏览器,所以我认为 firebug 或 fiddler 不适用 我认为@Tridus 的意思是通过它的Web 界面访问该站点并摆弄请求以查看是否可以匹配它。即使您有四个不同的值,其中之一是 xml,您也可以使用 xml 来编写整个帖子,或者 json 和 MVC 应该足够聪明,可以将对象放在一起。我知道至少 MVC 3 会做到这一点。 【参考方案1】:

包含所有这些请求和响应的客户端代码过于复杂且不安全。您没有对任何请求参数进行编码,更不用说这个 XML 如果您没有正确编码它可能会破坏一切。

出于这个原因,我将简化有关编码等的管道代码并将其留给 .NET 框架:

using (var client = new WebClient())

    var values = new NameValueCollection
    
         "uid", hwid ,
         "localization", localization ,
         "label", label ,
         "interchangeDocument", interchangeFile.OuterXml ,
    ;
    var result = client.UploadValues(controllerUrl, values);
    // TODO: do something with the results returned by the controller action

就服务器端而言,作为每个正确架构的 ASP.NET MVC 应用程序,它显然会使用视图模型:

public class MyViewModel

    public string Uid  get; set; 
    public string Localization  get; set; 
    public string Label  get; set; 
    public string InterchangeDocument  get; set; 

与:

[HttpPost]
public ActionResult Foo(MyViewModel model)

    // TODO: do something with the values here
    ...

显然,这可以通过编写反映 XML 文档结构的视图模型来更进一步:

public class Foo

    public string Bar  get; set; 
    public string Baz  get; set; 

然后您的视图模型将变为:

public class MyViewModel

    public string Uid  get; set; 
    public string Localization  get; set; 
    public string Label  get; set; 
    public Foo InterchangeDocument  get; set; 

最后一部分是为Foo 类型编写一个自定义模型绑定器,该绑定器将使用XML 序列化程序(或其他)将InterchangeDocument POST 值反序列化回Foo 实例。现在这是严肃的事情。

【讨论】:

感谢您提供完整的解决方案。我将尝试使用 WebClient 对象来简化事情。你说我没有对 xml 进行编码。字符串交换Xml = HttpUtility.UrlEncode(stringWriter.GetStringBuilder().ToString());这不是编码 xml 的正确方法吗? WebClient 只是收到 500 而不执行操作。既然动作需要一个视图模型,那么路由应该如何看待。我按照您的建议创建了一个 viewModel。 @Darin 我的 catch 块中的状态报告“协议错误”。 "远程服务器返回错误:(500) Internal Server Error" @Nick,看看内部异常。它应该是一个 HttpException,您可以从中提取来自服务器的确切响应消息。或者让您的服务器应用程序记录错误,以便您可以进一步缩小问题范围。恐怕从您提供的信息(应用程序抛出 500 状态码)中,我无法为您提供太多帮助。 @Darin 不幸的是,没有内部异常,并且异常并没有为我提供任何不那么模糊的东西。【参考方案2】:

我在这里和同一个野兽搏斗:Trying to set up a controller action as Xml endpoint

您可能会收到内部服务器错误,因为您启用了页面验证(解决方案:使用 ValidateInput(false) 添加),或者您没有在请求中发送 Accept-Encoding 标头。我非常想听听如何让 MVC 在没有 Accept-Encoding HTTP 标头的情况下接受发布的输入...

【讨论】:

【参考方案3】:

我刚刚发现您可以调用控制器,甚至是依赖注入的控制器,甚至可以从使用“T4MVC”Nuget 包的 Web 窗体代码后面调用:

https://github.com/T4MVC/T4MVC

【讨论】:

以上是关于如何使用 HttpWebRequest 将数据发布到 MVC 控制器?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HttpWebRequest 模拟浏览器文件上传

如何使用 c# 使用 httpwebrequest 从 json api 获取数据?

如何防止 HttpWebRequest 的数据包碎片

如何异步使用 HttpWebRequest (.NET)?

如何使用 HttpWebRequest 进行摘要身份验证?

如何通过httpwebrequest访问使用证书登录的网站