Exception -"Cannot send a content-body with this verb-type" using httpclient.sendasync - asp.net-web-api

Already tried searching SO for similar issues but those didn't help to resolve.
Scenario:
Have a Web Client app which has a Web API app as a backend. There is no issue when calling the same URI if it's from this Client - Web API but the exception happens when I'm trying to trigger the API request from another WebAPI Services application ( say its a separate project for accessing reports which run as a service using Telerik Reporting).
Code:
private async Task<HttpStatusCode> AccessService()
{
HttpResponseMessage response = null;
try
{
using (HttpRequestMessage request = new HttpRequestMessage()
{
Content = new System.Net.Http.StringContent(JSONValues, System.Text.Encoding.UTF8, "application/json"),
RequestUri = new Uri(UriString),
Method = CallMethod
})
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Utils.Token) ;
response = await httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
string httpResponse = await response.Content.ReadAsStringAsync();
httpString = JsonConvert.DeserializeObject<string[]>(httpResponse);
}
ErrorCode = response.StatusCode;
response.Dispose();
}
}
catch (Exception ex)
{
Misc.Error= ex.Message;
}
finally
{
response.Dispose();
}
return ErrorCode;
}
Exception:
Cannot send a content-body with this verb-type.
at System.Net.HttpWebRequest.CheckProtocol(Boolean onRequestStream)
at System.Net.HttpWebRequest.BeginGetRequestStream(AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.StartGettingRequestStream(RequestState state)
at System.Net.Http.HttpClientHandler.PrepareAndStartContentUpload(RequestState state)
--- 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.Net.Http.HttpClient.<FinishSendAsyncBuffered>d__58.MoveNext()
--- 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`1.GetResult()
This works fine when I access the same from the Client app ( asp.net mvc ) and issue happens when I call this from the Report Services API app. Is this has something to with it.
Edit:
The Web client Project is asp.net mvc core 2.1, so I think it works while using content in GET method of HttpClient.SendAsync but the Reports Services App where this issue happens are targets .net 461 .
I strongly doubt this might be the cause since .net framework doesn't allow content for GET operations? Any work arounds?
Link
TIA

Based on the description provided, if you use get method you usually don't have a body in the get request. For more details, please refer to the solutions below:
http://stackoverflow.com/questions/3981564/cannot-send-a-content-body-with-this-verb-type

Related

Catastrophic failure(Exception HRESULT: 0x8000FFFF (E_UNEXPECTED)) while trying to use MS WebView2 in ASP,NET Web API in production environment

I'm getting 'Catastrophic failure(Exception HRESULT: 0x8000FFFF (E_UNEXPECTED))' run-time error while trying to use MS WebView2 in ASP.NET Web API in production environment (Win10, IIS v.20H2 (OS Build 19042, 1586)) - see details in the code inline.
When the same code is used in a .NET Framework console app or under VS2019/Kestrel(?) (Ctrl+F5 - Start without debugging) everything works well.
private ManualResetEvent _event;
public void StartBrowserThread()
{
var th = new Thread(async () =>
{
BrowserFormsLogger.Log($"th.Context = {contextDescription}");
var webView = new Microsoft.Web.WebView2.WinForms.WebView2();
...
udf = ...
var envTask = await Microsoft.Web.WebView2.Core.CoreWebView2Environment
.CreateAsync(userDataFolder: udf);
var ecwTask = webView.EnsureCoreWebView2Async(envTask);
while (ecwTask.IsCompleted == false)
{
Application.DoEvents();
//
// Run-time error happens here in ASP.NET environment after .DoEvents called several thousand times.
// In a .NET Framework Console App everything works well.
//
// WebView2 creation failed with exception = System.Runtime.InteropServices.COMException (0x8000FFFF):
// Catastrophic failure(Exception HRESULT: 0x8000FFFF (E_UNEXPECTED))
// in System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
// in Microsoft.Web.WebView2.Core.CoreWebView2Environment.<CreateCoreWebView2ControllerAsync>d__58.MoveNext()
// --- End of stack trace from previous location where exception occurred ---
// in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
// in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
// in System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
// in Microsoft.Web.WebView2.WinForms.WebView2.<InitCoreWebView2Async>d__18.MoveNext()
};
...
_event.Set();
System.Windows.Forms.Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.IsBackground = true;
_event = new ManualResetEvent(false);
th.Start();
...
Any clues how this issue can be solved?

Where is the exception information when I return InternalServerError from a Web Api?

I'm calling one Web Api (.NET Framework) from another (.NET Core). If the called one returns an InternalServerError(exception), how do I access that exception from the calling code?
The called one does this:
public IHttpActionResult GetAccountTransactions()
{
try
{
// do some stuff
}
catch (Exception e)
{
return InternalServerError(e);
}
}
The calling one does this:
HttpResponseMessage response = await client.GetAsync(url);
...but when I add the response to the watch window in Visual Studio, I can't find the exception information.
Using Fiddler, I confirmed that the exception was included in the response body but it took some work to extract it.
See How can I retrieve passed exception from HttpResponseMessage(HttpStatusCode, Exception)
I tested this answer posted there with .NET Framework, but not with .NET Core.
if(!response.IsSuccessStatusCode){
HttpError error = response.Content.ReadAsAsync<HttpError>().Result;
}

Upload a text file as attachment using Bot framework not working in Skype channel

I am unable to upload a text file as an attachment using the Bot framework (Bot.Builder v3.11.0), when trying in the Skype channel. It worked in the Bot framework emulator though. Following is the code which uploads a file and to returns the activity with the uploaded file URL in the attachment. It throws an exception when using the Skype channel. Alternatively is there any other way to achieve uploading/attaching a text file in the Skype channel which the user can then download from within the client?
public static async Task<Activity> GetTextAttachmentAsync(Activity message)
{
var reply = message.CreateReply("Here is a text attachment");
var serviceUrl = reply.ServiceUrl;
var conversationId = reply.Conversation.Id;
byte[] fileData = null;
using (var wc = new System.Net.WebClient())
fileData = wc.DownloadData("https://textfiles.com/100/adventur.txt");
using (var connector = new ConnectorClient(new Uri(serviceUrl)))
{
var attachments = new Attachments(connector);
var token = await (connector.Credentials as MicrosoftAppCredentials).GetTokenAsync();
connector.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await attachments.Client.Conversations.UploadAttachmentAsync(
conversationId,
new AttachmentData
{
Name = "transcript.html",
OriginalBase64 = fileData,
Type = "text/html"
});
reply.Attachments = new List<Attachment>
{
new Attachment
{
Name = "transcript.html",
ContentType = "text/html",
ContentUrl = attachments.GetAttachmentUri(response.Id)
}
};
return reply;
}
}
Exception thrown from the UploadAttachmentAsync() function above:
Microsoft.Rest.HttpOperationException: Not Found
at Microsoft.Bot.Connector.ErrorHandling.<HandleErrorAsync>d__2`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Connector.ConversationsExtensions.<UploadAttachmentAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Support.Services.Bot.Core.Utilities.AdaptiveCardsHelper.<GetTextAttachmentAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Support.Services.Bot.Core.Dialogs.BotDialog.<HandleMessageAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Support.Services.Bot.Core.Dialogs.DialogBase`1.<MessageReceivedAsync>d__8.MoveNext()
When running your code with Common Language Runtime Errors enabled in Visual Studio. I got the following error:
It seems that the site address https://textfiles.com/100/adventur.txt does not have a trusted certificate and that makes .NET unhappy. When I went to investigate, I found this Stack Overflow answer that suggested using this code below to overcome this but is strongly recommended not to use this in production.
ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true;
This was going to be my original suggestion before I ran your code: many channels (Skype included), limit the types of files you are able to send from a bot when using base64 and/or local files. For example, I know that you cannot send PDF files as Base64 in Skype. If memory serves correctly, you can only send image and video files (maybe audio too) using the base64 method in Skype. So even if you resolve this error you may run into this afterward. The workaround for this is using hosted files. I'm not exactly sure what you are trying to do with your bot, so I'm not sure if this is an option for you specifically, but it is an option.
So if you find this code not working after resolving the certificate issue, try sending an image file and see if that works, if it does but your HTML file still fails, you will know this is why.

Web API Post hit before HttpWebRequest has finished streaming a large file

In our app (Silverlight 5 out-of-browser client hitting a WebApi server) we routinely use an HttpClient for posting/getting/deleting and so on all our entities between client and server. This all works fine most of the time, but recently we have run into an issue when uploading (posting) larger entities (> 30/35mb): we start the streaming process and BEFORE it is finished our Post method on the Web API is hit, receiving a null entity.
We can't understand what is going on, and suspect there must be some timing issue related since it all depends on the size of the upload.
To further explain, our client in summary is doing this:
HttpResponseMessage response = await _client.SendAsync(request);
string jsonResult = await response.Content.ReadAsStringAsync();
... where _client is our HttpClient and request our HttpRequestMessage. In case it is also relevant (I am trying not to flood the question with code :), the content in the request is created like this:
request.Content = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
Well, when we debug this the Post method on our server is hit before the await _client.SendAsync(request) finishes, which sort of "explains" why it is receiving a null entity in such cases (larger entities), where when it works that await call is finished and THEN the Post is hit.
In case if sheds more light into it, due to certain limitations on the HttpClient (regarding access to AllowWriteStreamBuffering), we have also tested an equivalent scenario but using directly an HttpWebRequest... unfortunately, the behavior is exactly the same. This is the relevant extract:
httpRequest.BeginGetRequestStream(RequestStreamCallback, httpRequest);
(where httpRequest is our HttpWebRequest with AllowWriteStreamBuffering = false), and the callback to handle the request stream is as follows:
private void RequestStreamCallback(IAsyncResult ar)
{
var request = ar.AsyncState as System.Net.HttpWebRequest;
if (request != null)
{
var requestStream = request.EndGetRequestStream(ar);
var streamWriter = new StreamWriter(requestStream) {AutoFlush = true};
streamWriter.Write(_jsonContent);
streamWriter.Close();
requestStream.Close(); // Belt and suspenders... shouldn't be needed
// Make async call for response
request.BeginGetResponse(ResponseCallback, request);
}
}
Again, for larger entities when we debug the Post method on the Web API is hit (with a null parameter) BEFORE the streamWriter.Write finalizes and the streamWriter.Close is hit.
We've been reading all over the place and fighting with this for days on now. Any help will be greatly appreciated!
In case somebody runs into this, I finally figured out what was going on.
In essence, the model binding mechanism in the Web API Post method was throwing an exception when de-serializing the JSON, but the exception was somewhat "hidden"... at least if you did not know that much about the inner workings of the Web API, as was my case.
My Post method originally lacked this validation check:
var errors = "";
if (!ModelState.IsValid)
{
foreach (var prop in ModelState.Values)
{
foreach (var modelError in prop.Errors.Where(modelError => modelError != null))
{
if (modelError.Exception != null)
{
errors += "Exception message: " + modelError.Exception.Message + Environment.NewLine;
errors += "Exception strack trace: " + modelError.Exception.StackTrace + Environment.NewLine;
}
else
errors += modelError.ErrorMessage + Environment.NewLine;
errors += " --------------------- " + Environment.NewLine + Environment.NewLine;
}
}
return Request.CreateErrorResponse(HttpStatusCode.NoContent, errors);
}
This is a "sample" check, the main idea being verifying the validity of the ModelState... in our breaking scenarios is wasn't valid because the Web API hadn't been able to bind the entity, and the reason could be found within the Errors properties of the ModelState.Values. The Post was being hit ok, but with a null entity, as mentioned.
By the way, the problem was mainly caused by the fact that we weren't really streaming the content, but using a StringContent which was attempted to be de-serialized in full... but that is another story, we were mainly concerned here with not understanding what was breaking and where.
Hope this helps.

NotSupportedException when adding entity via odata on windows phone

I'm using the odata client generator (DataSvcUtil.exe) in a Windows Phone 7 application. Retrieving entities and collections is fine as is updating an existing entity. But when I try to add a new entity, I get a NotSupportedException. Here's my code.
private void Button_Click(object sender, RoutedEventArgs e)
{
Drinks d =new Drink();
d.BarCode = "1234567890";
d.Description = "Test Drink";
d.Quantity = -1;
context.AddToDrinks(d);
context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context);
}
private void OnChangesSaved(IAsyncResult result)
{
Dispatcher.BeginInvoke(() =>
{
try
{
var something = result.AsyncState;
context = result.AsyncState as DrinkTrackerModelContainer;
// Complete the save changes operation and display the response.
ShowSaveResponse("Drink Logged!", context.EndSaveChanges(result));
}
catch (DataServiceRequestException ex)
{
ShowSaveResponse("Error Logging Drink", ex.Response);
}
catch (InvalidOperationException ex)
{
ShowSaveResponse(ex.Message, null);
}
}
);
}
As soon as EndSaveChanges is called, I get the
NotSupportedException.
EDIT: I used fiddler and saw that I was in fact getting a different exception from the service. That exception data was not being shown in the debugger. Once I corrected the actual exception, the insert worked fine.
I think you have first chance exceptions turned on which is causing an internal exception thrown by the client library to surface as an exception. Try turning off First Chance Exceptions in the "Exceptions" menu in VS and running the app.
As you mentioned in your edit, the NotSupportedException was a red herring. I think that when debugging a phone app you will hit the NotSupportedException even if you have cleared the setting to break on unhandled CLR exceptions.
If you continue(F5), you'll hit an actual DataServiceRequestException exception. If it doesn't have enough information to debug it, you can follow the steps in this post to get more detailed information in the exception: http://blogs.msdn.com/b/phaniraj/archive/2008/06/18/debugging-ado-net-data-services.aspx
I ran into the same problem yesterday, and after following the steps in the blog I was able to successfully debug the problem.

Resources