I have created a self hosted WEB API, which works pretty well. While returning an object through HttpResponseMessage, I get an exception in the client code. Exception reads - "The underlying connection was closed: An unexpected error occurred on a receive." and the Message is "An error occurred while sending the request.". Kindly see attachment.
Client Code:
internal async Task<object> AddBuiltInAsync(string featureType, Dictionary<string, string> specAttr)
{
int rc = -1;
object returnedFeatureId = null;
try
{
FormUrlEncodedContent formContent = new FormUrlEncodedContent(specAttr);
string jsonSpecAttr = JsonConvert.SerializeObject(specAttr);
HttpResponseMessage response = await Client.PostAsync($"DWGImplODA/AddBuiltIn?featureType={featureType}&jsonSpecAttr={jsonSpecAttr}", formContent).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
object returnedFeatureId = await response.Content.ReadAsAsync<object>().ConfigureAwait(false);
// returnedFeatureId = JsonConvert.DeserializeObject<object>(jsonReturnedFeatureId);
}
else
{
_logger.Info("AddBuiltInAsync: Failed");
}
}
catch (Exception ex)
{
_logger.Error("AddBuiltInAsync: Exception - " + ex);
}
return returnedFeatureId;
}
Server Code:
[HttpPost]
public IHttpActionResult AddBuiltIn(string featureType, string jsonSpecAttr)
{
HttpResponseMessage response = null;
object returnedFeatureId = null;
string jsonReturnedFeatureId = string.Empty;
try
{
Dictionary<string, string> specAttr = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonSpecAttr);
integrationImpl = (IIntegrationImpl)cacheObject.Get("integrationImpl");
integrationImpl.AddBuiltIn(featureType, specAttr, out returnedFeatureId);
//jsonReturnedFeatureId = JsonConvert.SerializeObject(returnedFeatureId);
}
catch (System.Exception ex)
{
Console.WriteLine("AddBuiltIn Exception - ", ex.StackTrace);
}
return Ok(returnedFeatureId);
}
As an alternative I have also tried returning a json string.
However, controller fails to serialize the object(of a complex type Teigha.Runtime.RxClass) and returns nothing to the client. I am using json 6.0.0.0 for serialization and deserialization.
Any help would be nice.
Note: Not sure though, but I think previously I was able to return "Object" directly without using HttpResponseMessage or Json.
Related
So, I am using postman to test this post method and its working as expected when i am posting/uploading small size file, close to 1MB, but its throwing error when uploading bigger file, 8MB+.
Line where its throwing error:-
await Request.Form.Files[0].CopyToAsync(ms).ConfigureAwait(false);
Error:-
Request.Form.Files = 'Request.Form.Files' threw an exception of type 'System.InvalidOperationException'
Its a Net Core 3.1 Application.
Adding the complete code if anyone want to replicate it.
[HttpPost("File")]
[SAPolicy(SAPolicy.Admin, SAPolicy.ConsumerApp)]
public async Task<IActionResult> PostFile()
{
FileContractRequest fileContract = null;
try
{
if (Request.ContentLength > 0)
{
using (var ms = new MemoryStream())
{
await Request.Form.Files[0].CopyToAsync(ms).ConfigureAwait(false);
var data = ms.ToArray();
var newFileContract = new FileContractRequest()
{
ContentType = Request.Form.Files[0].ContentType,
Name = Path.GetFileName(Request.Form.Files[0].FileName),
Length = data.LongLength.ToString(),
CreationDate = DateTime.UtcNow,
Data = data
};
fileContract = newFileContract;
}
}
else
{
return new StandardResponse<FileContractResponse>(HttpStatusCode.NotAcceptable, null).Result;
}
}
catch (Exception ex)
{
throw ex;
}
var result = await _fileService.PostFile(fileContract).ConfigureAwait(false);
return new StandardResponse<FileContractResponse>(HttpStatusCode.OK, result).Result;
}
I looked in to couple of different blogs and could not find anything that helps me with my problem. Any help to fix this ? what i am missing here ?
Edit 1:-
My service is register with azzure notification hub. And using my .net server API it push notification to particular device within particular time frame.
Everything goes right except when I try to send multiple push in same code it stuck with "BadRequest" except first one.
Below is the code
public static async void SendAzzurePushNotification()
{
for (int i = 0; i < 10; i++)
{
HttpStatusCode pushNotificationStatus = await CreateAndPushAsync("user_37");
Console.WriteLine(pushNotificationStatus);
}
}
static async Task<HttpStatusCode> CreateAndPushAsync(string tag)
{
HttpStatusCode pushNotificationStatus = HttpStatusCode.NotImplemented;
try
{
HttpResponseMessage response = null;
string uri = "<HUBURI>";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("SharedAccessSignature", <SASTOKEN>);
client.DefaultRequestHeaders.Add("ServiceBusNotification-Format", "gcm");
client.DefaultRequestHeaders.Add("ServiceBusNotification-Tags", tag);
client.DefaultRequestHeaders.Add("x-ms-version", "2015-01");
response = await client.PostAsync(uri,
new StringContent("{\"data\":{\"message\":\"Notification Hub test notification\"}}", Encoding.UTF8, "application/json"));
pushNotificationStatus = response.StatusCode;
}
catch (Exception ex)
{
throw;
}
return pushNotificationStatus;
}
Above code give me Created status for first time and then BadRequest after that. If same api I call from client like postman. It work fine.
I also tried nuget package from azure notification hub, regarding which code is as below. Which solve my above issue but it won't return me any status code which I can have in my above code for success.
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<CONNECTIONSTRING>", "<HUB>");
NotificationOutcome outcome = await hub.SendGcmNativeNotificationAsync("{\"data\":{\"message\":\"Notification Hub test notification\"}}", "user_37");
Call send method with your tags and your notification-data
private static readonly string Endpoint = #"Your End Point";
private static readonly string HubName = #"You Hub Name";
private static NotificationHubClient Hub { get { return NotificationHubClient.CreateClientFromConnectionString(Endpoint, HubName); } }
public static async Task Send(string[] tags, object data)
{
try
{
string payload = string.Empty;
string json_gcm = string.Empty;
if (data.GetType() != typeof(string))
{
//If your notification data is of type
payload = JsonConvert.SerializeObject(data);
json_gcm = "{ \"data\" : " + payload + "}";
}
else
{
//If your notification data is simply is in string
payload = Convert.ToString(data);
json_gcm = "{ \"data\" : {\"message\":\"" + payload + "\"}}";
}
// Android
NotificationOutcome gcmOutcome = null;
gcmOutcome = await Hub.SendGcmNativeNotificationAsync(json_gcm, tags);
if (gcmOutcome != null)
{
if (!((gcmOutcome.State == NotificationOutcomeState.Abandoned) || (gcmOutcome.State == NotificationOutcomeState.Unknown)))
{
//Do code when notification successfully send to Android
}
}
}
catch (Exception ex)
{
//Do code when any exception occurred while sending notification
}
}
NotificationOutcomeState: Gives you status code in the form of enum that represent your notification has been successfully sent or not.
You may ignore if-else block as your need.
Try once may it help you
I am new with Async and await using C# Programming. In WebAPI, we have created two API Controllers one with Async and await Programming and other is without that. We have done load testing using JMeter and we have got following results.
Users Sync Async
100 No Errors No Errors
500 No Errors No Errors
750 No Errors Errors - (59.0 %) - 502 Bad Gateway
763 No Errors Errors
764 No Errors Errors
765 Errors - (0.13 %) - 502 Bad Gateway Errors
1000 Errors Errors
Can you any please explain/suggest which approach is best or how can we proceed ?
API Code :
GetPersonalDetailsController - Async and await Used
public async Task<IHttpActionResult> GET([FromUri] RequestQueryListDTO objAPIRequest)
{
DateTime startResponseTime = DateTime.Now;
Response objResponse = null;
string strResponse = string.Empty;
var HeaderType = Request.Content.Headers.ContentType;
ProductBAL objProductBAL = null;
try
{
if (objAPIRequest != null)
{
Task<Response> tskGetProductDetails = Task<Response>.Run(() =>
{
objProductBAL = new ProductBAL();
return objProductBAL.GetProductDetails(objAPIRequest);
//Business Access Layer Logic calling
});
objResponse = await tskGetProductDetails;
}
else
{
objResponse = new Response();
objResponse.ReturnCode = -1;
objResponse.ReturnMessage = "Missing Parameters.";
}
}
catch (Exception ex)
{
\\ Exception Logging
}
finally
{
objProductBAL = null;
}
objResponse.ResponseTime = Math.Round((DateTime.Now - startResponseTime).TotalMilliseconds).ToString();
if (objResponse.ReturnCode == Convert.ToInt32(General.ReturnCode))
{
return Content<Response>(HttpStatusCode.BadRequest, objResponse);
}
else
{
return Ok(objResponse);
}
}
========================================================================
GetPDPController - Without using Async and await
public IHttpActionResult GET([FromUri] RequestQueryListDTO objAPIRequest)
{
DateTime startResponseTime = DateTime.Now;
Response objResponse = null;
string strResponse = string.Empty;
var HeaderType = Request.Content.Headers.ContentType;
try
{
if (objAPIRequest != null)
{
//Business Access Layer Logic calling
}
else
{
objResponse = new Response();
objResponse.ReturnCode = -1;
objResponse.ReturnMessage = "Missing Parameters.";
}
}
catch (Exception ex)
{
// Exception Logging Code
}
finally
{
objProductBAL = null;
}
objResponse.ResponseTime = Math.Round((DateTime.Now - startResponseTime).TotalMilliseconds).ToString();
if (objResponse.ReturnCode == Convert.ToInt32(General.ReturnCode))
{
return Content<Response>(HttpStatusCode.BadRequest, objResponse);
}
else
{
return Ok(objResponse);
}
}
My suggestion is have two methods, one Async and one not. That way you can test more.
GetProductDetails
GetProductDetailsAsync
you would then need to change the signature of the calling method aka GET
public IHttpActionResult GET([FromUri] RequestQueryListDTO objAPIRequest)
{
var objResponse = new Response();
//check the properties of objAPIRequest
if(bad)
{
//add stuff if you want
return Content<Response>(HttpStatusCode.BadRequest, objResponse);
}
//Business Access Layer Logic calling
//-----------------------
ProductBAL objProductBAL = new ProductBAL();
//you need to change this to async
var productDetails = objProductBAL.GetProductDetails(objAPIRequest);
//-----------------------
return Ok(objResponse);
}
Here is my code:
private Message SendMessage(ref Message message, string serviceURL)
{
Message result = null;
try
{
IRequestChannel channel = null;
BasicHttpBinding binding = ...;
using (var cf = new ChannelFactory<IRequestChannel>(binding, new EndpointAddress(serviceURL)))
{
foreach (OperationDescription op in cf.Endpoint.Contract.Operations)
{
op.Behaviors.Remove<DataContractSerializerOperationBehavior>();
}
cf.Open();
channel = cf.CreateChannel();
channel.Open();
result = channel.Request(message);
channel.Close();
cf.Close();
channel = null;
}
binding = null;
}
catch (Exception ex)
{
Logger.LogError("Error parsing SOAP", ex.Message);
}
return result;
}
On line result = channel.Request(message);
I get an error posted below in a picture. However, I get it only when I turn "Break when" CLR exceptions occur. When I don't debug, my code doesn't go to the catch block.
Looks like you try serialize or deserialize string with value = 'X' to bool. I think you should check contract or check your message object.
Somewhere inside .net code calls XmlConvert.ToBoolean(String) method. Valid values for it 0 or 1 Link to doc
I currently have to provide a sync as async method in my API: Please find the code below. The only problem is that I don’t have a
sync method in the backend. I use Azure.NotificationHub client. That client has only *Async methods. Is my way reasonable?
public PushHubNotificationResult SendPushMessage(string userId, string message)
{
PushHubNotificationResult result = new PushHubNotificationResult();
try
{
result = SendPushMessageAsync(userId, message).GetAwaiter().GetResult();
} catch (Exception ex)
{
result.Status = PushHubNotificationResultType.Error;
result.Error = ex.Message;
result.Exception = ex;
}
return result;
}
public async Task<PushHubNotificationResult> SendPushMessageAsync(string userId, string message)
{
PushHubNotificationResult result = new PushHubNotificationResult();
// EnableTestSend see: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-fixer/#self-diagnose-tips
// Create a new Notification Hub client.
Microsoft.Azure.NotificationHubs.NotificationHubClient hub =
Microsoft.Azure.NotificationHubs.NotificationHubClient.CreateClientFromConnectionString(NotificationHub, NotificationHubName);
// Sending the message so that all template registrations that contain "messageParam"
// will receive the notifications. This includes APNS, GCM, WNS, and MPNS template registrations.
Dictionary<string, string> templateParams = new Dictionary<string, string>();
templateParams["messageParam"] = message;
string userTag = "_UserId:" + userId; // That line sets the IMEI or SerialNo (WLAN only device) == userId to which the push message is sent
try
{
// Send the push notification and log the results.
NotificationOutcome outcome = await hub.SendTemplateNotificationAsync(templateParams, userTag);
result.Status = PushHubNotificationResultType.Success;
foreach (RegistrationResult hubResult in outcome.Results)
{
result.PushNotificationHub = hubResult.ApplicationPlatform;
result.RegistrationId = hubResult.RegistrationId;
result.Outcome = hubResult.Outcome;
}
}
catch (System.Exception ex)
{
result.Status = PushHubNotificationResultType.Error;
result.Error = ex.Message;
result.Exception = ex;
}
return result;
}
thanks for any advice,
Eric
If you want to use sync-over-async, it's very important that you use ConfigureAwait(false) in your async code, otherwise you are very likely to get a deadlock.
NotificationOutcome outcome =
await hub.SendTemplateNotificationAsync(templateParams, userTag).ConfigureAwait(false);
The async method already converts exceptions to PushHubNotificationResultType.Error, why does the sync version do it too?