How to call a WCF method asynchronously from MVC4 WebAPI - c#

I am new to the WebApi, .Net world and am totally confused with all the information available as to what approach I should take. I have created a WebService using MVC4 WebApi that Twilio calls when a text message is received. I need to respond to this text message. I am consuming a WCF method which is currently being called synchronously. Since it is possible that my process can take longer than 3-5 seconds to process a reply to the text message the connection to Twilio gets disconnected due to timeout. So I am looking for ways to call this WCF method asynchronously.
My question is to call the WCF method (I am calling the WCF using a Object Factory and using)
do I need to update the contract to say Async? I am little confused on that.
BTW my Web Service is in IIS7 and am using .Net4.5 framework and MVC4 WebApi .
My code is somewhat like this: So I would like to call the SendSms part asynchronously. How do I do that? Can I simply use Task.Run Async and Await?
using Twilio.Mvc;
using Twilio.TwiML.Mvc;
using Twilio.TwiML;
public class SmsController : ApiController
{
[HttpPost]
public HttpResponseMessage Post([FromBody]SmsRequest smsReq)
{
var response = new Twilio.TwiML.TwilioResponse();
//validation checks..
try
{
-- call to WCF to get the List of sms to be sent
if ((txtMessageResponse != null) && (txtMessageResponse.SmsMessageInfo.Count > 0))
{
_smsStagingList = txtMessageResponse.SmsMessageInfo;
foreach (TextMessageStaging prepareTextMessageResponse in _smsStagingList)
{
smsDTO textMessageItems = new smsDTO();
textMessageItems.PhoneNumber = prepareTextMessageResponse.PhoneNumber;
textMessageItems.SmsMessage = prepareTextMessageResponse.SmsMessageBody;
isTxtMessageSent = SendSms(textMessageItems);
//If the messages were sent then no need to set the flag to be updated
if (isTxtMessageSent)
{
txtMessageStatusToBeUpdated = false;
}
}
return Request.CreateResponse(HttpStatusCode.OK, twilioResponse.Element);
}
else
{
//send error response
}
catch (Exception msgProcessingError)
{
//send error response again as processing error
}
finally
{
//set the outbound flag in the table
}
}
private bool SendSms(smsDTO textMessageItems)
{
bool isTxtMessageSent = false;
PushMessageRequest txtMessageRequest = new PushMessageRequest();
PushMessageResponse txtMessageResponse = null;
txtMessageRequest.SmsMessageInfo = new SendTextMessage(); //instantiate the dto
txtMessageRequest.SmsMessageInfo.ToPhone = textMessageItems.PhoneNumber;
txtMessageRequest.SmsMessageInfo.TextMessage = textMessageItems.SmsMessage;
try
{
using (ITextService textService = ObjectFactory.SendSmsMessage())
{
txtMessageResponse = textService.SendSmsMessage(txtMessageRequest);
}
isTxtMessageSent = txtMessageResponse.IsSuccessful;
}
catch (Exception ex)
{
isTxtMessageSent = false;
}
return isTxtMessageSent;
}

Twilio evangelist here.
OK, so you have a Web API method in which you call a WCF method that is potentially long running. There are two problems to solve here:
How do you call the WCF method in a way that does not block the Web API method from returning a response
How do you get Twilio to wait until the WCF method has finished
I wrote a blog post a while ago that shows you how to create an indefinite wait loop in an IVR by leveraging .NET's Task Parallel library and the loop attribute on Twilios <Play> verb.
The gist of the post is that you can use the TPL's StartNew method to start the long running WCF method on a new thread. This lets ASP.NET continue and lets you return some TwiML so Twilio does not end the call. Then you pair that with a continuation which lets you know when the WCF service request is done and you can signal back to Twilio using the REST API to redirect the in-progress call to a new set of TwiML instructions.
Hope that helps.

Related

.NET Core GetFromJsonAsync exits with no error or debugging information

I am trying to debug a request by GetFromJsonAsync which is supposed to fetch data from a Flask API and convert to JSON within a .NET Core cli app.
The issue I am having however is that after performing the request the cli app simply exits with no error. I have tried implementing try/catch block but nothing shows up there.
the Flask endpoint builds jsonifies a number of uuids and messages from Postgres and returns them to the client.
As GetFromJsonAsync is asynchronous I have tried making the Flask endpoint likewise but that has not seemed to help at all. The latter works fine and has been validated with curl.
I know the call executes as I can see it in my web server logs.
A similar call which simply returns plain javascript object {"foo": "bar"} works fine which is why I think this could by an async issue but I cannot see any errors etc to troubleshoot. I have placed a breakpoint on the foreach after the call but this is never hit.
What am I missing here?
public static async void GetMessages()
{
ConfigureHeaders();
try
{
var client = Client;
var res = await Client.GetFromJsonAsync<Received>(Url + "/api/chat/message"); // stops here
foreach (var c in res!.messages) // breakpoint here is never hit
Console.WriteLine(c);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public class Received
{
public Dictionary<string,string> messages { get; set; }
}
Flask
#message.get("/api/chat/message")
#csrf.exempt
async def get_messages():
new_msgs = {}
msgs = await get_unreplied() # DB gets called from another function here
try:
for m in msgs:
new_msgs[m.id] = m.message
if len(new_msgs) != 0:
return jsonify(new_msgs)
else:
return jsonify("no messages")
except Exception as e:
print(str(e))
This returns...
{
"id_foo1": "message_bar1",
"id_foo2": "message_bar2"
}
Best guess: your Main function is not awaiting the call to GetMessages
public async Task<int> Main(string []args)
{
await GetMessages();
}

If another request is running a method wait until finish

I'm developing an ASP.NET Web API application with C#, .NET Framework 4.7 and MongoDb.
I have this method:
[HttpPut]
[Route("api/Public/SendCommissioning/{serial}/{withChildren}")]
public HttpResponseMessage SendCommissioning(string serial, bool withChildren)
{
string errorMsg = "Cannot set commissioning.";
HttpResponseMessage response = null;
bool serverFound = true;
try
{
[...]
// Mongo
MongoHelper mgHelper = new MongoHelper();
mgHelper.InsertCommissioning(serial, withChildren);
}
catch (Exception ex)
{
_log.Error(ex.Message);
response = Request.CreateResponse(HttpStatusCode.InternalServerError);
response.ReasonPhrase = errorMsg;
}
return response;
}
Sometimes this method is called very quickly and I get an error here:
// Mongo
MongoHelper mgHelper = new MongoHelper();
mgHelper.InsertCommissioning(serial, withChildren);
Here I'm inserting the serials I received in order, and sometimes I get an error with a duplicated key in MongoDb:
I have a method to get the latest id used in Mongo (the primary key). And two requests get the same id, so when I try to insert it on Mongo I get an invalid key exception.
I thought to use a queue to store the serials and then consume them in the same order that I have received them. But I think I will get the same error when I try to store the serial in MongoDb.
Maybe if I can set a method that if it is running, I have to wait to run it, it will works. This method will have the part of insert the serials into Mongo.
How can I do that? A method that if it is running you can't run it in another Web Api request.
Or, do you know a better option?
By the way, I can't block this method. Maybe I need to run a thread with this synchronized part.

How to Implement Progress Bar for Long Running HTTP Request

I have an HTTP server written in C# based off the HttpListenerContext class. The server is for processing binary log files and converting them to text, and can take quite a long time to do the conversion. I would like to indicate progress back to the user, but I am unsure on the best way to do this. On the server side, in handling my HTTP request, I essentially have this function:
public async Task HandleRequest()
{
try
{
await ProcessRequest();
}
catch (HttpListenerException)
{
// Something happened to the http connection, don't try to send anything
}
catch (Exception e)
{
SendFailureResponse(500);
}
}
Currently, ProcessRequest() sends the HTML response when finished, but I would like to essentially add the IProgress interface to the function and somehow indicate that progress back to the Web client. What is the best way to do this?
One way of doing it would be to store progress on server side and periodically pull the information from client.
However, if you want the server to notify the client ( push ), then you will need to implement some kind of bi-directional communication between the server and client (I am currently using ASP.NET Web API and SignalR to achieve this at work).
Here is what I got I'll try to explain and I hope you notice its not FULL FULL complete, you'll have to understand the logic behind this and accept or not as a plausible option.
The Method: Set a custom object to store progress of your ongoing operations, make a global static list containing this metadata. Notice how I track them with Ids: I don't store that on DB, the natural act of instantiating the class will auto_increment their Id.
Then, you can add a new controller to respond the progress of a particular ongoing process.
Now that you have a controller to respond the progress of an ongoing process by Id, you can create a javascript timer to call it and update the DOM.
When creating your process, dont hold the htmlrequest until its over, open a background operation instead and just respond with the newly created ProgressTracker.Id, through that class/list you can keep track of the progress and reply accordingly.
As said in another answer, when an operation finishes you can send a push notification and the clientside javascript will interrupt the timers and proceed to the next view/result/page, or you can increment the looping timer to detect when its done and call the results from another controller. (this way you can avoid using push if needed.)
Here is the partial code:
public class ProgressTracker {
private static GlobalIdProvider = 0;
public int _id = ++GlobalIdProvider;
public int Id { get { return _id; } }
bool IsInProgress = false;
bool IsComplete = false;
float Progress;
public YourProgressObject Data;
}
public class GlobalStatic {
public static List<ProgressTracker> FooOperations = new List<ProgressTracker>();
}
public class SomeWebApiController {
[HttpGet]
[Authorize]
public HttpResponseMessage GetProgress(int Id) {
var query = (from a in GlobalStatic.FooOperations where a.Id==Id select a);
if(!query.Any()) {
return Request.CreateResponse(HttpStatusCode.NotFound, "No operation with this Id found.");
} else {
return Request.CreateResponse(HttpStatusCode.Ok, query.First());
}
}
}
// this is javascript
// ... Your code until it starts the process.
// You'll have to get the ProgressTracker Id from the server somehow.
var InProgress = true;
window.setTimeout(function(e) {
var xmlhttp = new XMLHttpRequest();
var url = "<myHostSomething>/SomeWebApiController/GetProgress?Id="+theId;
xmlhttp.setRequestHeader("Authentication","bearer "+localStorage.getItem("access_token"));
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var data = JSON.parse(xmlhttp.responseText);
updateProgressBar(data);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
function updateProgressBar(data) {
document.getElementById("myProgressText").innerHTML = data.Progress;
}
}, 3000);
Disclaimer: If my javascript is shitty, pardon me but I'm too used to using jQuery and all this fancy stuff x_x

WebService how to not wait until task is completed

I have a c# function inside a WebService to save the records being modified or added.
public bool UpdateEmployeeInfo(DataSet ds, int userId) {
bool returnVal = true;
Guid employeeUid = Guid.Empty;
SqlConnection conn = new SqlConnection(InfoTacto.Framework.WebServices.Common.GetConnectionString());
conn.Open();
SqlTransaction trans = conn.BeginTransaction(IsolationLevel.ReadUncommitted, "UpdateEmployeeInfo");
try {
if (ds != null && ds.Tables.Contains("employee") && ds.Tables["employee"].Rows.Count > 0) {
DataRow mainRow = ds.Tables["employee"].Rows[0];
employeeUid = new Guid(mainRow["employeeUid"].ToString());
}
// depending on the tables being modified, _sendMessage can be true or false
_sendMessage = EmployeeUpdate.UpdateEmployeeMethods(ds, trans, userId);
trans.Commit();
} catch (Exception err) {
trans.Rollback();
returnVal = false;
} finally {
//if(conn.State == ConnectionState.Open)
conn.Close();
}
// send push message for real time sync
if (_sendMessage) {
// this service sometimes take between 1 to 5 seconds so I dont want to wait
// until it has finished...
Utility.MessageService sqs = new MessageService();
sqs.SendMessage("employeeUid=" + employeeUid);
}
return returnVal;
}
After all tables are updated successfully I check I the webservice needs to send a Message (to other system), this action sometimes takes milliseconds or up to 5 seconds but I don't want my Desktop application to freeze waiting for my webservice function to complete.
// this service sometimes take between 1 to 5 seconds so I dont want to wait
// until it has finished...
Utility.MessageService sqs = new MessageService();
sqs.SendMessage("employeeUid=" + employeeUid);
Any clue on how can I leave the server to complete that SendMessage function so my UpdateEmployeeInfo wont wait for it to complete in order to return my returnVal value to my client application.
Thanks
Have you tried:
Task t = Task.Run(()=>
{
Utility.MessageService sqs = new MessageService();
sqs.SendMessage("employeeUid=" + employeeUid);
});
You should consider not sending the message to the other system directly, regardless of whether you do it on another thread or not. Instead, decouple the systems using a queue. Push the message onto the queue and exit, then have the other system read from the queue.
There are lots of queuing infrastructures to consider, including MSMQ, Azure Storage Queues, Azure Service Bus Queues, RabbitMQ, and lots more.
If you generate the client for Utility.MessageService using the latest WCF svcutil (version 4.5.1), it will actually generate asynchronous versions of your method calls for you. You could then call sqs.SendMessageAsync(), which won't wait around after the message is sent.
Here's an example Service interface:
[ServiceContract]
public interface IEmailService
{
[OperationContract]
void SendEmail(EmailDTO email);
}
using the 4.5.1 version of svc util, here is an excerpt from the generated client. Notice that there is a Async version of SendEmail(), SendEmailAsync():
public partial class EmailServiceClient : System.ServiceModel.ClientBase<IEmailService>, IEmailService
{
. . .<SNIP> . . .
public void SendEmail(EmailDTO email)
{
base.Channel.SendEmail(email);
}
public System.Threading.Tasks.Task SendEmailAsync(EmailDTO email)
{
return base.Channel.SendEmailAsync(email);
}
}
For me, the latest version of svcutil was in C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\svcutil. This version generated the accompanying Async versions of my service methods. Earlier version of svcutil, also on my machine, did not generate the Async versions.

Xamarin Android Questions and Issues when working with WebServices (SOAP .NET 2.0)

I've been working with Xamarin and Webservices (Stated as .NET 2.0 Webservice in Xamarin) in the past few weeks. And I've runned into a few problems that I couldn't figure a workaround yet.
1st) How do I set a timeout for the webservice? The Timeout property is ignored regardless of its value. I believe the default being used is something around 30 seconds. But I'd like 5 seconds~~.
2nd) When the WebService call any method async, using the Begin. Is there anyway to check whether the async method was completed correctly or was timed out? The only way I got to "check" is by perfoming a try/catch in the End method. If it was fired because of a timeout, it will raise an exception. But I wonder if there is some property or method somewhere that would tell me if the webservice call did timeout or was processed correctly. The webservice method being used here is "IsAlive".
WebService.MainService.BeginIsAlive ((ar) =>
{
try
{
bool result = WebService.MainService.EndIsAlive (ar); //If timedout will raise an exception.
RunOnUiThread (() =>
{
Toast.MakeText (this, "Running as expected...", ToastLength.Long).Show();
});
StartActivity (typeof(OtherScreen));
}
catch (Exception ex)
{
//Probably timeout.
}
}, null);
3rd) Is there a way to Cancel a webservice async operation? Such as "CancelIsAlive". The only method I found was Webservice.Abort. But I do not believe it is a best practice and since it is not specific, it may screw everything up.
Thanks in advance, Luís Henrique.
That's what usually I do for calling WebServices and having control on them (assume your ws function needs an string and returns an string):
public static void CallSomeFunction(string SomeParameter, Action<string> Ok, Action Error, Activity Context)
{
ThreadPool.QueueUserWorkItem ((object e) => {
var proxy = new YourProxyClass();
proxy.Timeout = 10000;
try{
var res = proxy.YourFunction(SomeParameter);
Context.RunOnUiThread(() => Ok(res));
}
catch(Exception Ex){
if(Error != null)
Context.RunOnUiThread(Error);
}
});
}
This is how I do asynchronous tasks, use the ThreadPool to make synchronous calls, and pass some Actions to execute if all is ok or wrong. Also I'm passing a Context so my Ok and Error actions be executed in the UI thread.

Categories

Resources