Converting EAP web service call to await/async - c#

I have a web reference which uses the Event-based Asynchronous Pattern. I am trying to convert this to use the Task based model so that I can use await/async. However I am having issues with this as it does not seem to do the call. I am using MonoTouch C# for this project.
Earlier I found this Stack overflow post which seemed to detail what I'm trying to do: How can I use async/await to call a webservice?
I managed to setup these methods and this is what my code looks like so far:
Authentication
var client = new AgentService();
GetUserDetailsCompletedEventArgs response = await client.GetUserDetailsAsyncTask(username, password);
if (response.Result != null)
// Do stuff
Agent Service Extensions
public static Task<GetUserDetailsCompletedEventArgs> GetUserDetailsAsyncTask(this AgentService client, string username, string password)
{
var source = new TaskCompletionSource<GetUserDetailsCompletedEventArgs>(null);
client.GetUserDetailsCompleted += (sender, e) => TransferCompletion(source, e, () => e);
client.GetUserDetailsAsync(username, password);
return source.Task;
}
private static void TransferCompletion(TaskCompletionSource<GetUserDetailsCompletedEventArgs> source, AsyncCompletedEventArgs e, Func<GetUserDetailsCompletedEventArgs> getResult)
{
if (e.UserState == source)
if (e.Cancelled)
source.TrySetCanceled();
else if (e.Error != null)
source.TrySetException(e.Error);
else
source.TrySetResult(getResult());
}
At the moment the GetUserDetailsAsyncTask method is called and the event handler is set but is never reached. After the await line is called the statement underneath it is never reached either and just skips to the end of the method. No error message is displayed and no exception is thrown. I'm not sure where I'm going wrong and I'd appreciate any guidance to help me solve this.

Related

Method Prerequisites

The Situation
I'm working on a OAuth2 Api Wrapper. Some api routes are for logged people and some for anonymous and logged.
Here is an example of one method in my wrapper :
public async Task<UploadListResponse> List(bool pagination = false, int page = 1, int limit = 10)
{
var request = UploadRequests.List(pagination, page, limit);
var cancellationTokenSource = new CancellationTokenSource();
var restResponse = await Context.Client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return restResponse.Handle<UploadListResponse>();
}
I build a request with all parameter set up then execute the request and then handle the answer in case I have an api error and then output an object containing all the data that request gave me.
The problem
With OAuth2, when you log to the API you'll receive an access token and a refresh token. If your access token is expired you have to contact the api with your refresh token to get a fresh new access token.
As I said earlier some of my method needs you to be logged but if your access token is expired I want to try to refresh token before throwing an exception like with this method :
public async Task<bool> NeedRelog()
{
try
{
var validAuth = await ValidAuth();
}
catch
{
try
{
var refresh = await Refresh(Context.Client.Config.RefreshToken);
}
catch
{
return true;
}
}
return false;
}
ValidAuth check with the API if you are logged and if I have an exception then I'll try to refreshToken.
I want to tag method that need logged to call NeedRelog() and those who aren't tag to not call it.
I may just do it in every method but it wouldn't be clean.
What I've done so far
I've found a great tool : PostSharp that seems to fit my needs.
I've started to do a checkLog aspect like this :
[Serializable]
public class CheckLog : OnMethodBoundaryAspect, IOnStateMachineBoundaryAspect
{
public CheckLog()
{
ApplyToStateMachine = false;
}
public override void OnEntry(MethodExecutionArgs args)
{
var instance = (ApiService)args.Instance;
var res = instance.Parent.OAuth.NeedRelog().Result;
if (!res)
{
args.Exception = new Exception("Need to relog");
args.FlowBehavior = FlowBehavior.Return;
}
}
}
Where I'm stuck
The Main problem is with the call to my NeedRelog() Method. Due to the fact this is an async method I'm struggling to make my aspect await for it.
If my OnEntry method is async then It won't block the call if you are not logged.
If my OnEntry method is not async and I wait for needLog it freeze and nothing happen.
I really want to know to use this kind of "conditional method call" with postsharp, it looks awesome but the fact is after looking for hours in the documentation I didn't find a way to do what I want.
I'm starting to ask myself if it is even possible to achieve what I'm aiming to do.
Did you try using a way to make the call synchronous maybe with something like this stackoverflow.com/a/25097498/3131696 ? – M22an 5 hours ago
As I can't mark a comment as answering a question I quote your comment to make this question answered as it is said here : link
Thanks you for this M22an.

WebAuthenticationResult - System.NotImplementedException

I am trying to implement Facebook authentication sample,
when code reaches at;
WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.None,loginUrl);
I am getting exception like below;
Exception = {System.NotImplementedException: Not implemented
at
Windows.Security.Authentication.Web.WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions
options, Uri requestUri) at
SonglyWindowsPhone.Views.Login.d__0.MoveNext()
--- End ...
Message: The method or operation is not implemented.
Is there any workaround for this?
In WinRT it's similar situation to FilePickers - you have to use AuthenticateAndContinue method. Once you use the method, your app is deactivated and after finished authentication it will be activated, at that moment you should handle OnActivated event in app.xaml.cs:
protected async override void OnActivated(IActivatedEventArgs args)
{
base.OnActivated(args);
var continuationEventArgs = args as IContinuationActivatedEventArgs;
if (continuationEventArgs != null)
{
switch (continuationEventArgs.Kind)
{
case ActivationKind.WebAuthenticationBrokerContinuation:
ValueSet data = continuationEventArgs.ContinuationData;
// continue web authentication
break;
// rest of code
At the WebAuthenticationBroker class you will also find a link to a sample.
And here at MSDN is nice explanation with sample code.

Response.Redirect issue with Asp.net async

I'm new to asp.net 4.5 async and am running into the following with calling response.redirect within an async method. The issue is that the response just "hangs" Has anyone else experienced similar issues with attempting an redirect with async? This code will work in a brand new project, but, does not work with a new page in our existing code. I made sure to gut out everything I could out of our web.config and removed our master page. Hitting a brick wall...any ideas? Thanks!
protected void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(PageLoadAsync));
}
private async Task PageLoadAsync()
{
var data = await GetData();
if (data == HttpStatusCode.OK)
Response.Redirect("http://www.google.com");
}
private async Task<HttpStatusCode> GetData()
{
using (var client = new HttpClient())
{
var response = await client.GetAsync("https://www.google.com");
return response.StatusCode;
}
}
This code will work in a brand new project, but, does not work with a new page in our existing code.
I assume your existing site has already been upgraded to .NET 4.5.
The first thing to check is that httpRuntime.targetFramework is set to 4.5. This is not set by default when you upgrade.
Edit from comments:
Another thing to check (just in case) is that Page.Async is set to true.
In this case, the solution was to call Response.Redirect("http://www.google.com", false), which explicitly passes false for the endResponse parameter. The default value of true is only for backwards-compatibility reasons as described here.
The hack I used is:
I used a static dictionary as var d= new Dictionary<string, bool>(); in the class where my API calling method is written.
I put the code line client.timeout = new System.TimeSpan(0,0,60); for API sending the request.
When API is timed out, it throws the TaskTimeoutException, in the TaskTimeoutExceptioncatch block write code as d.Add("timeout", true);
Now, I created the custom action filter and applied the following code:
public class MyCustomActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if(MyApiClass.d.ContainsKey("timeout") && d["timeout"])
{
throw new Exception();
}
}
}
I applied the [MyCustomActionFilter ] on the action.
When action is executed and enter the custom filter it throws Exception by checking the dictionary entry.
If timeout would have occurred then dictionary entry will be true, so, on the basis of that, we check the entry and throws the exception. Now, we have Application_Error() in Global.asax.cs that catches the exception.
In the Application_Error() we have written the code for redirect to the required page.
NOTE: In step 4 you can create your custom exception to provide more precise detail for logging.

Checking internet connectivity in Windows8 via C# fails

I'm trying to test the Internet connection in Windows8 from my C# application. I have a variable of type Boolean that returns me the connection status. When the boolean is true: do nothing. When the boolean becomes false, load my "NetworkDisconection" page. However, when I debug this line:
if (this.Frame != null)
I get an exception:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
Yeah, this method is on a different thread. How can I resolve this?
private bool bConection;
public HUB()
{
this.InitializeComponent();
bConection = NetworkInformation.GetInternetConnectionProfile()!= null;
NetworkInformation.NetworkStatusChanged += NetworkInformation_NetworkStatusChanged;
}
void NetworkInformation_NetworkStatusChanged(object sender)
{
if (NetworkInformation.GetInternetConnectionProfile() == null)
{
if (bConection == false)
{
bConection = true;
}
}
else
{
if (bConection == true)
{
bConection = false;
if (this.Frame != null)
{
Frame.Navigate(typeof(NetworkDisconection));
}
}
}
}
Use the following code and it should fix your problem...
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
if (this.Frame != null)
{
Frame.Navigate(typeof(NetworkDisconection));
}
});
You should be able to acquire the Dispatcher directly since it looks like your code is in the code-behind of a XAML page (reference to this.Frame).
Tons of good info can be found in the C# Win8 Dev Forums. Search for Dispatcher and you will find several discussions on it. As always, check out GenApp for other great resources.
The NetworkInformation.NetworkStatusChanged event is raised on a non-UI thread. Similar to WinForms and WPF, you are still limited to accessing controls on the UI thread.
To get around this aspect, you'll have to invoke the UI thread similar to how you would on WinForms or WPF using this.Invoke/this.Dispatcher.Invoke.
At first you may try to use Window.Current.Dispatcher.RunAsync() but you will notice that Window.Current is always null here.
Instead, you should use CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync() in the Windows.ApplicationModel.Core namespace. Yeah, that's quite a mouthful for sure so I recommend this helper method in App.cs.
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
public static IAsyncAction ExecuteOnUIThread(DispatchedHandler action)
{
var priority = CoreDispatcherPriority.High;
var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
return dispatcher.RunAsync(priority, action);
}
I would also recommend this helper method too:
public static bool CheckInternetAccess()
{
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile == null) return false;
var connectivityLevel = profile.GetNetworkConnectivityLevel();
return connectivityLevel.HasFlag(NetworkConnectivityLevel.InternetAccess);
}
And finally:
async void NetworkInformation_NetworkStatusChanged(object sender)
{
var isConnected = CheckInternetAccess();
await ExecuteOnUIThread(() =>
{
if (!isConnected && this.Frame != null)
this.Frame.Navigate(typeof(ConnectionLostPage));
});
}

Calling C# ASMX Web Service

I have an ASMX web service that I need to utilise as part of a piece of work. I am calling this service via an ASPX page to create new entities on a 3rd party system. I have no access to the underlying code to that service, its simply to allow me to communicate with another system.
Im having trouble finding out if I am calling the service correctly and I wonder if anyone could offer some advice.
I have installed the ASMX page and that has given me a class 'ConfirmConnector' which I call the BeginProcessOperations method. I want to wait on that to return and then parse te results. The results should be in XML which I then step through to get the data I am after.
The trouble is that sometimes this process just dies on me, i.e. when I call my 'EndProcessOperations' method then nothing happens. I dont get an error, nothing - my code just dies and the method returns'
My calling code is:
private void sendConfirmRequest(XmlManipulator requestXML)
{
file.WriteLine("Sending CONFIRM Request!");
AsyncCallback callBack = new AsyncCallback(processConfirmXML); // assign the callback method for this call
IAsyncResult r = conn.BeginProcessOperations(requestXML, callBack, AsyncState);
System.Threading.WaitHandle[] waitHandle = { r.AsyncWaitHandle }; // set up a wait handle so that the process doesnt automatically return to the ASPX page
System.Threading.WaitHandle.WaitAll(waitHandle, -1);
}
My handler code is :
/*
* Process the response XML from the CONFIRM Connector
*/
private static void processConfirmXML(IAsyncResult result)
{
try
{
file.WriteLine("Received Response from CONFIRM!");
if(result == null)
{
file.WriteLine("RESPONSE is null!!");
}
if(conn == null)
{
file.WriteLine("conn is null!!");
}
file.WriteLine("Is Completed : " + result.IsCompleted);
XmlNode root = conn.EndProcessOperations(result);
file.WriteLine("got return XML");
//writeXMLToFile("C:/response.xml",root.InnerXml);
file.WriteLine(root.InnerXml);
Can anyone advise if I am handling this code in the correct way and does anyone have any idea why my code randomly bombs after this line in the handler :
XmlNode root = conn.EndProcessOperations(result);
Thanks for your help,
Paul
thanks for looking, but I solved my problem. The issue appeared to be related to my callback operation.
I changed the code to call my begin & end methods in the same block of code and I havent had an issue since then.
private void sendConfirmRequest(XmlManipulator requestXML)
{
//ConfirmConnector conn = new ConfirmConnector();
file.WriteLine("Sending CONFIRM Request!");
//AsyncCallback callBack = new AsyncCallback(processConfirmXML); // assign the callback method for this call
//IAsyncResult r = conn.BeginProcessOperations(requestXML, callBack, AsyncState);
//System.Threading.WaitHandle[] waitHandle = { r.AsyncWaitHandle }; // set up a wait handle so that the process doesnt automatically return to the ASPX page
//System.Threading.WaitHandle.WaitAll(waitHandle, -1);
file.WriteLine("Calling BeginProcessOperations");
IAsyncResult result = conn.BeginProcessOperations(requestXML, null, null);
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
file.WriteLine("Calling EndProcessOperations");
XmlNode root = conn.EndProcessOperations(result);
processConfirmXML(root);
file.WriteLine("got return XML");
//writeXMLToFile("C:/response.xml",root.InnerXml);
file.WriteLine(root.InnerXml);
// Close the wait handle.
result.AsyncWaitHandle.Close();
}
Thanks
Paul

Categories