WP8 SDK import Service Reference with task-based operations not possible - web-services

So far it seems that importing a service reference in VS2012 with "generate task-based operations" is not working. It os greyed out.
A test with a new project for WPF is working fine - I could select either task-based or async operations.
Is there a simple way on wrapping the async call in a task?

Is there a simple way on wrapping the async call in a task?
Example for WebClient.DownloadStringCompleted
public static class WebClientAsyncExtensions
{
public static Task<string> DownloadStringTask(this WebClient client, Uri address)
{
var tcs = new TaskCompletionSource<string>();
DownloadStringCompletedEventHandler handler = null;
handler = (sender, e) =>
{
client.DownloadStringCompleted -= handler;
if (e.Error != null)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(e.Result);
}
};
client.DownloadStringCompleted += handler;
client.DownloadStringAsync(address);
return tcs.Task;
}
}
Usage:
async void DownloadExample()
{
WebClient client = new WebClient();
await client.DownloadStringTask(new Uri("http://http://stackoverflow.com/questions/13266079/"));
}

Related

Unit testing Armeria's decorator using context.log().whenComplete()

I have a subclass of SimpleDecoratingHttpService that contains something like this:
override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
ctx.log().whenComplete().thenAccept {
if (it.responseCause() == ...) {
// do stuff
}
}
return unwrap().serve(ctx, req)
}
I want to test the logic inside the whenComplete() callback. However, when writing tests like this:
myDecorator.serve(context, request).aggregate().join()
the log() future never completes. What do I need to do to ensure that the log() future eventually completes?
Emulating RequestLog completion
A RequestLog is completed by Armeria's networking layer, so just consuming an HttpRequest or HttpResponse will not complete a RequestLog. To complete it, you need to call the methods in RequestLogBuilder:
var myDecorator = new MySimpleDecoratingHttpService(...);
var ctx = ServiceRequestContext.of(
HttpRequest.of(HttpMethod.GET, "/hello"));
var req = ctx.request();
var res = myDecorator.serve(ctx, ctx.req).aggregate().join();
// Fill the log.
ctx.logBuilder().endRequest();
assert ctx.log().isRequestComplete();
ctx.logBuilder().responseHeaders(ResponseHeaders.of(200));
ctx.logBuilder().endResponse();
assert ctx.log().isComplete();
Armeria team uses the same technique for testing BraveService, so you might want to check it out as well at BraveServiceTest.java:161.
Testing with a real server
If your setup is too complex to use a mock, as an alternative approach, you can launch a real Armeria server so that Armeria fills the log for you. You can easily launch a server using ServerRule (JUnit 4) or ServerExtension (JUnit 5):
class MyJUnit5Test {
static final var serviceContexts =
new LinkedBlockingQueue<ServiceRequestContext>();
#RegisterExtension
static final var server = new ServerExtension() {
#Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/hello", (ctx, req) -> HttpResponse.of(200));
sb.decorator(delegate -> new MySimpleDecoratingHttpService(delegate, ...));
// Record the ServiceRequestContext of each request.
sb.decorator((delegate, ctx, req) -> {
serviceContexts.add(ctx);
return delegate.serve(ctx, req);
});
}
};
#BeforeEach
void clearServiceContexts() {
serviceContexts.clear();
}
#Test
void test() {
// Send a real request.
var client = WebClient.of(server.httpUri());
var res = client.get("/hello").aggregate().join();
// Get the ServiceRequestContext and its log.
var ctx = serviceContexts.take();
var log = sctx.log().whenComplete().join();
// .. check `log` here ..
assertEquals(200, log.responseHeaders().status().code());
}
}

Manual pause and resume functionality in AWS SWF java framework

Does SWF natively supports manual pause and resume workflow functionality in java framework? If not is there any way to achieve to achieve that semantics?
Edit: I implemented following example, seems to be working with initial testing. Is there anything which can break with this. My workflow is going to be long running (~3-5 hours) with same activity being multiple times with different params.
import com.amazonaws.services.simpleworkflow.flow.annotations.Asynchronous;
import com.amazonaws.services.simpleworkflow.flow.core.Promise;
import com.amazonaws.services.simpleworkflow.flow.core.Settable;
public class GreeterWorkflowImpl implements GreeterWorkflow {
private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl();
Settable<Void> paused = new Settable<>();
public void greet() {
Promise<String> fs = getGreeting(0, operations.getName());
print(fs);
}
#Asynchronous
private Promise<String> getGreeting(int count, Promise<String> name)
{
if (count > 10)
return name;
return getGreeting(count, name, paused);
}
#Asynchronous
private Promise<String> getGreeting(int count, Promise<String> name, Settable<Void> paused) {
Promise<String> returnString = operations.getGreeting(name.get());
return getGreeting(count + 1, returnString);
}
#Asynchronous
private void print(Promise<String> finalString)
{
System.out.println("Final String is " + finalString.get());
}
// #Signal method
#Override
public void pause() {
paused = new Settable<>();
}
// #Signal method
#Override
public void resume() {
paused.set(null);
}
}
In case you get multiple signals for resume, you will be setting the paused settable again (which is already ready) so you might end up with unhandled IllegalStateException

How to get a CompletableFuture from Jetty's HttpClient?

Is it possible to use issue an asynchronous HTTP request using Jetty and get back a CompletableFuture?
I read the docs but could not find any examples of doing so. I found internal usage of CompletableFuture but I couldn't figure out how to access it using the public API.
UPDATE: I need the CompletableFuture to return the response body as well (not just the response code and headers).
I have been using this with jetty client 9.4.x
var completable = new CompletableFuture<ContentResponse>();
client
.newRequest(uri)
.send(new CompletableFutureResponseListener(completable));
where
public class CompletableFutureResponseListener extends BufferingResponseListener {
private final CompletableFuture<ContentResponse> completable;
public CompletableFutureResponseListener(
CompletableFuture<ContentResponse> completable) {
this.completable = completable;
}
#Override
public void onComplete(Result result) {
if (result.isFailed()) {
completable.completeExceptionally(result.getFailure());
} else {
var response =
new HttpContentResponse(
result.getResponse(),
getContent(),
getMediaType(),
getEncoding());
completable.complete(response);
}
}
}
It's trivial to convert a CompleteListener into a CompletableFuture in this way:
CompletableFuture<Result> completable = new Promise.Completable<>();
httpClient.newRequest(...).send(result -> {
if (result.isFailed()) {
completable.completeExceptionally(result.getFailure());
} else {
completable.complete(result);
}
});
However, you are right that this may be done by HttpClient itself. Track this issue.

The system crashes and can not display the error message

assume the code is correct and webservice timeout occurs.
The problem :
The system crashes and can not display the error message.
How to display error message? So I can provide an alternative to user when there is an error?
1)
I add this Class in the project :
public class MyClass
{
public static async Task LogInSuccess()
{
try
{
-- calling a web service here
}
catch (System.Exception _ex)
{
_strErrorMsg = _ex.InnerException.Message;
throw new Exception("LogInSuccess() " + _strErrorMsg);
}
}
}
--- In the MainPage,
2)
private async void SetUp ()
{
-- code for doing setUp task--
CallWebSvc();
}
3)
private void CallWebSvc()
{
bool ShowError = false;
System.Exception MyException = new Exception();
try
{
-- calling a web service thru the MyClass
System.Threading.Tasks.Task _blnLogInSuccess = MyClass.LogInSuccess();
await _blnLogInSuccess;
if (_blnLogInSuccess.IsCompleted)
{
g_blnLoginStatus = _blnLogInSuccess.Result;
}
}
catch (System.Exception _ex)
{
ShowError = true;
MyException = ex;
}
if (ShowError)
{
var MyMessageBox = new Windows.UI.Popups.MessageDialog("Remote Login Error:" + MyException.Message, "Start Login" );
await MyMessageBox.ShowAsync();
}
}
I assume your CallWebSvc method is async void (as, without async you cannot perform an await) If this is the case, you need to know async void doesn't do the same treatament to exceptions as async task. they aren't catched correctly. If you change your CallWebSvc from async void to async Task, you are going to receive the exception correctly.

WinRT App consume NAV web services and got this message

I did the following and got the below error msg:
The error message :
An exception of type 'System.AggregateException' occurred in mscorlib.dll but was not handled in user code
Additional information: One or more errors occurred.
If there is a handler for this exception, the program may be safely continued.
Question :
a) What seems to be the problems in above code as I just wanted to retrieve a record.
b) Must use Async Methods in WinRT or Windows store app?
c) Will below code able to retrieve record from Navision?
-----1------- Windows store App to access Nav Web Services
1.1 Added the service reference in WinRT App
1.2 Added a class1.cs in WinRT App
private async void btnImportCustomer_Click(object sender, RoutedEventArgs e)
{
Task _asyncCustomer = Class1.Customer.Listing.GetAsyncRecords("Y007");
### encounterd error here: ####
string g_strmsg = _asyncCustomer.Result.No + " “ +_asyncCustomer.Result.Name;
}
-----2---------- Class1.cs use inside WinRT App Project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MobileNAVSalesSystem
{
class Class1
{
public static string _webserviceurlpage = "http ://{0}:{1}/{2}/WS/{3}/Page/{4}";
public static string _webserviceurlcodeunit = "http://{0}:{1}/{2}/WS/{3}/Codeunit/{4}";
public static Uri _webserviceuripage = null;
public static Uri _webserviceuricodeunit = null;
#region Customer
public class Customer
{
public class Card
{
//Do something for Card Type
}
public class Listing
{
public static wsCustomerList.Customer_List_PortClient GetService()
{
_webserviceuripage = new Uri(string.Format(_webserviceurlpage, "msxxx", "7047", "DynamicsNAV_xxx", Uri.EscapeDataString("Global xxx Pte. Ltd."), "Customer List"));
System.ServiceModel.BasicHttpBinding _wSBinding = new System.ServiceModel.BasicHttpBinding();
_wSBinding.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly;
_wSBinding.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
_wSBinding.MaxBufferSize = Int32.MaxValue;
_wSBinding.MaxReceivedMessageSize = Int32.MaxValue;
//_wSBinding.UseDefaultWebProxy = false;
wsCustomerList.Customer_List_PortClient _ws = new wsCustomerList.Customer_List_PortClient(_wSBinding, new System.ServiceModel.EndpointAddress(_webserviceuripage));
_ws.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
_ws.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("xxx","xxxx", "companyName");
return _ws;
}
//-------------------------- Using Async Methods
public static async Task GetAsyncRecords(string _No)
{
wsCustomerList.Customer_List_PortClient _ws = GetService();
wsCustomerList.Customer_List _List = (await _ws.ReadAsync(_No)).Customer_List;
if (_ws.State == System.ServiceModel.CommunicationState.Opened)
await _ws.CloseAsync();
return _List;
}
public static async Task GetAsyncRecords(wsCustomerList.Customer_List_Filter[] _filters)
{
wsCustomerList.Customer_List_PortClient _ws = GetService();
wsCustomerList.Customer_List[] _List;
List _filterArray = new List();
_filterArray.AddRange(_filters);
_List = (await _ws.ReadMultipleAsync(_filterArray.ToArray(), null, 0)).ReadMultiple_Result1;
if (_ws.State == System.ServiceModel.CommunicationState.Opened)
await _ws.CloseAsync();
return _List;
}
public static async Task GetAsyncRecords(wsCustomerList.Customer_List_Filter[] _filters, string _bookmarkkey)
{
wsCustomerList.Customer_List_PortClient _ws = GetService();
wsCustomerList.Customer_List[] _List;
List _filterArray = new List();
_filterArray.AddRange(_filters);
_List = (await _ws.ReadMultipleAsync(_filterArray.ToArray(), _bookmarkkey, 0)).ReadMultiple_Result1;
if (_ws.State == System.ServiceModel.CommunicationState.Opened)
await _ws.CloseAsync();
return _List;
}
public static async Task GetAsyncRecords(wsCustomerList.Customer_List_Filter[] _filters, string _bookmarkkey, int _setsize)
{
wsCustomerList.Customer_List_PortClient _ws = GetService();
wsCustomerList.Customer_List[] _List;
List _filterArray = new List();
_filterArray.AddRange(_filters);
_List = (await _ws.ReadMultipleAsync(_filterArray.ToArray(), _bookmarkkey, _setsize)).ReadMultiple_Result1;
if (_ws.State == System.ServiceModel.CommunicationState.Opened)
await _ws.CloseAsync();
return _List;
}
}
}
#endregion
}
//--- end namespace
}
i know it is some time ago this question was posted, but others might stumble across it, so here goes:
a) What seems to be the problems in above code as I just wanted to retrieve a record.
it seems like your return type is incorrect.
b) Must use Async Methods in WinRT or Windows store app?
Yes, when using windows mobile platforms(windows store apps and windows phone apps), you have to use asynchronous calls.
c) Will below code able to retrieve record from Navision?
Hard to tell, but to me it seems like your data you try to retrieve is in a incorrect format. Ill give you a simple example from one of my current projects where I retrieve a login:
private async void Button_Click(object sender, RoutedEventArgs e)
{
await call();
}
private async Task call()
{
BasicHttpBinding binding = new BasicHttpBinding();
NetworkCredential cred = new NetworkCredential("username", "password", "domain");
WS_PortClient ws = new WS_PortClient(binding, new EndpointAddress("Webservice-URL"));
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
ws.ClientCredentials.Windows.ClientCredential = cred;
CheckLogin_Result s = await ws.CheckLoginAsync("parameter");
string k = s.return_value.ToString();
MessageDialog d = new MessageDialog(k, "message");
await d.ShowAsync();
}
Hope it helps!