为什么我不能正确调用此API来将对象传递给请求主体?

时间:2018-11-23 11:53:09

标签: c# .net asp.net-mvc httpwebrequest asp.net-apicontroller

.NET C#(我来自Java和Spring框架)中,我是一个新手,我发现以下以正确方式调用API的困难。

我将尝试详细解释我的问题。

我有这个API(已定义到部署到IIS中的项目中。请注意,该项目还包含我正在调用的其他API,没有问题)

[HttpPost]
[Route("api/XXX/InviaAlProtocollo/{siglaIDUor}")]
public string InviaAlProtocollo(MailBuffer mailBuffer, string siglaIDUor)
{
    ..........................................................................
    DO SOMETHING
    ..........................................................................
}

如您所见,它带有2个输入参数:

  • MailBuffer mailBuffer ,应该放在请求正文中。
  • 进入URI的
  • siglaIDUor

尝试传递第一个参数时遇到一些问题。

注意:我无法更改此API的代码,因为它是由其他人制作的,并且可能会对其他事物产生影响。

进入另一个部署在其他地方的项目中,我试图以这种方式(从控制器方法)调用以前的API:

[SharePointContextWebAPIFilter]
[HttpGet]
[ActionName("InviaMailAlProtocollo")]
public IHttpActionResult InviaMailAlProtocollo(string siglaIdUor)
{

    Console.WriteLine("INTO InviaAlProtocollo()" + siglaIdUor);

    // Ignore self signed certificate of the called API:
    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

    // Create the byte array[]
    UTF8Encoding encoding = new UTF8Encoding();
    byte[] mailContent = encoding.GetBytes("TEST");

    // Create the MailBuffer object that have to be passed to the API into the request body:
    MailBuffer content = new MailBuffer();
    content.Nome = "blablabla";
    content.Buffer = mailContent;

    string jsonRequest = urlBaseProtocolloApi + "/api/XXX/InviaAlProtocollo/ABC123";

    // Setting my credentials:
    credCache.Add(new Uri(jsonRequest), "NTLM", myCreds);

    HttpWebRequest spRequest = (HttpWebRequest)HttpWebRequest.Create(jsonRequest);
    spRequest.Credentials = credCache;
    spRequest.UserAgent = "Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0";
    spRequest.Method = "POST";
    spRequest.Accept = "application/json;odata=verbose";
    spRequest.ContentType = "application/json; charset=UTF-8";

    // Create and set the stream:
    spRequest.ContentLength = mailContent.Length;

    Stream newStream = spRequest.GetRequestStream();
    newStream.Write(mailContent, 0, mailContent.Length);

    newStream.Close();

    // Obtain the response from the API:
    HttpWebResponse endpointResponse = (HttpWebResponse)spRequest.GetResponse();

    string sResult;
    JArray jarray;

    // Parse the response:
    using (StreamReader sr = new StreamReader(endpointResponse.GetResponseStream()))
    {
        sResult = sr.ReadToEnd();

        jarray = JArray.Parse(sResult);
        //JObject jobj = JObject.Parse(sResult);
    }

    Console.WriteLine(jarray);

    return Ok(jarray);

}

问题是,当此方法调用我的API时,收到的 MailBuffer mailBuffer 输入参数为 null (我看到它调试了我的API并调用了它)。

我怀疑问题可能与呼叫的此代码段有关:

// Create and set the stream:
spRequest.ContentLength = mailContent.Length;

Stream newStream = spRequest.GetRequestStream();
newStream.Write(mailContent, 0, mailContent.Length);

newStream.Close();

可能是我尝试将错误的内容附加到请求的正文中( byte [] mailContent ,而不是整个 MailBuffer内容对象)。

注意:要执行此呼叫,我必须使用 HttpWebRequest

那么,怎么了?我想念什么?如何解决此问题,将整个 MailBuffer内容对象放入正文请求中,并允许我调用的API将其检索为输入参数?

3 个答案:

答案 0 :(得分:4)

另一个项目应确保该请求是使用另一个API期望的正确格式的数据发出的。

现在,您只在请求的正文中发送测试电子邮件的原始字节

//...

// Create the byte array[]
UTF8Encoding encoding = new UTF8Encoding();
byte[] mailContent = encoding.GetBytes("TEST");

// Create the MailBuffer object that have to be passed to the API into the request body:
MailBuffer content = new MailBuffer();
content.Nome = "blablabla";
content.Buffer = mailContent;

//...

Stream newStream = spRequest.GetRequestStream();
newStream.Write(mailContent, 0, mailContent.Length); //<---HERE ONLY SENDING encoding.GetBytes("TEST")

另一个端点期望可以反序列化为MailBuffer的数据

这是应重构以发送正确数据的代码部分

//...

UTF8Encoding encoding = new UTF8Encoding();
// Create the MailBuffer object that have to be passed to the API into the request body:
var content = new MailBuffer() {
    Nome = "blablabla",
    Buffer = encoding.GetBytes("TEST")
};
//convert model to JSON using Json.Net
var jsonPayload = JsonConvert.SerializeObject(content);
byte[] mailContent = encoding.GetBytes(jsonPayload); //<---CORRECT CONTENT NOW

spRequest.ContentLength = mailContent.Length;

Stream newStream = spRequest.GetRequestStream();
newStream.Write(mailContent, 0, mailContent.Length);

//...

最后,我建议使用HttpClient的简单API发出请求。但这完全取决于您的喜好。

以下是使用HttpClient进行相同呼叫的示例

[SharePointContextWebAPIFilter]
[HttpGet]
[ActionName("InviaMailAlProtocollo")]
public async Task<IHttpActionResult> InviaMailAlProtocollo(string siglaIdUor) {
    Console.WriteLine("INTO InviaAlProtocollo()" + siglaIdUor);
    // Ignore self signed certificate of the called API:
    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

    string requestUri = urlBaseProtocolloApi + "/api/XXX/InviaAlProtocollo/" + siglaIdUor;
    // Setting my credentials:
    credCache.Add(new Uri(requestUri), "NTLM", myCreds);

    var handler = new HttpClientHandler {
        UseDefaultCredentials = true,
        Credentials = credCache
    };

    var client = new HttpClient(handler);
    client.DefaultRequestHeaders.Add("UserAgent", "Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json;odata=verbose"));

    // Create the MailBuffer object that have to be passed to the API into the request body:
    var buffer = new MailBuffer() {
        Nome = "blablabla",
        Buffer = Encoding.UTF8.GetBytes("TEST")
    };
    //convert model to JSON using Json.Net
    var jsonPayload = JsonConvert.SerializeObject(buffer);
    var mailContent = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
    // Obtain the response from the API:
    var response = await client.PostAsync(requestUri, mailContent);
    if (response.IsSuccessStatusCode) {
        var jarray = await response.Content.ReadAsAsync<JArray>();
        Console.WriteLine(jarray);
        return Ok(jArray);
    }
    return BadRequest();
}

答案 1 :(得分:2)

使用[FromBody]参数。

[HttpPost]
[Route("api/XXX/InviaAlProtocollo/{siglaIDUor}")]
public string InviaAlProtocollo([FromBody]MailBuffer mailBuffer, string siglaIDUor)
{
    ..........................................................................
    DO SOMETHING
    ..........................................................................
}

还尝试将MailBuffer作为JSON对象传递,当您从正文传递时,它将自动转换为MailBuffer对象。

如果这样做不起作用,请在具有相似对象的方法中切换MailBuffer对象,然后将该对象映射到MailBuffer。

答案 2 :(得分:1)

您可以尝试使用HttpClient (using System.Net.Http)

private static readonly HttpClient client = new HttpClient();

// Create the MailBuffer object that have to be passed to the API into the request body:
MailBuffer content = new MailBuffer();
content.Nome = "blablabla";
content.Buffer = mailContent;

var values = new Dictionary<string, object>
{
   { "mailBuffer", content },
   { "siglaIDUor", siglaIdUor }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("/api/XXX/InviaAlProtocollo/ABC123", content);

var responseString = await response.Content.ReadAsStringAsync();