How to use Visual Studio - generated async WCF calls? - c#

My OperationContract:
public List<MessageDTO> GetMessages()
{
List<MessageDTO> messages = new List<MessageDTO>();
foreach (Message m in _context.Messages.ToList())
{
messages.Add(new MessageDTO()
{
MessageID = m.MessageID,
Content = m.Content,
Date = m.Date,
HasAttachments = m.HasAttachments,
MailingListID = (int)m.MailingListID,
SenderID = (int)m.SenderID,
Subject = m.Subject
});
}
return messages;
}
In Service Reference configuration I checked the option "Generate asynchronous operations". How do I use the generated GetMessagesAsync()? In the net I found examples that use AsyncCallback, however I'm not familiar with that. Is there a way to use it in some friendly way like async and await keywords in .NET 4.5? If not, what should I do to invoke the method asynchronously?

If you select 'Generate asynchrounous operations', you will get the 'old' behavior where you have to use callbacks.
If you want to use the new async/await syntax, you will have to select 'Generate task-based operations' (which is selected by default).
When using the default Wcf template, this will generate the following proxy code:
public System.Threading.Tasks.Task<string> GetDataAsync(int value) {
return base.Channel.GetDataAsync(value);
}
As you can see, there are no more callbacks. Instead a Task<T> is returned.
You can use this proxy in the following way:
public static async Task Foo()
{
using (ServiceReference1.Service1Client client = new ServiceReference1.Service1Client())
{
Task<string> t = client.GetDataAsync(1);
string result = await t;
}
}
You should mark the calling method with async and then use await when calling your service method.

Your Service Reference can (if you are using .Net 4.5) be set to generate task-based async calls. (Configure Service Reference > check Allow generation of asynchronous operations > select Generate task-based operations) These can be used like any async method. Here's an example of how to use it:
using (var proxy = new YourServiceClient())
{
var t1 = proxy.GetMessagesAsync();
var t2 = proxy.GetMessagesAsync();
//they're runnning asynchronously now!
//let's wait for the results:
Task.WaitAll(t1, t2);
var result1 = t1.Result;
var result2 = t2.Result;
Console.WriteLine(result1);
Console.WriteLine(result2);
}
If your client is not using .Net 4.5, you cannot generate service references that use async. You'll have to do it the old fashioned way, using callbacks. Here's an example:
static void m()
{
var proxy = new YourServiceClient();
proxy.GetMessagesCompleted += proxy_GetMessagesCompleted;
proxy.GetMessagesAsync();
}
static void proxy_GetMessagesCompleted(object sender, GetMessagesCompletedEventArgs e)
{
var proxy = (IDisposable)sender;
proxy.Dispose(); //actual code to close properly is more complex
if (e.Error != null)
{
// do something about this
}
var result = e.Result;
Console.WriteLine(result);
}
Note that in actual code for either of these scenarios, you shouldn't use using or IDisposable.Dispose() to clean up the client, see Avoiding Problems with the Using Statement and this code to get you started into the confusing world of closing these things.

If you're on VS2012, then you can use the *Async calls like this:
var proxy = new MyClient();
var result = await proxy.GetMessagesAsync();

How about something like this...
public async Task<string> DoSomething()
{
var someProxy = new ServiceClient();
var t = someProxy.SomeMethodAsync();
await Task.WhenAny(t);
return t.Result;
}

Related

Moq Test - Mocked Service Call Always Returns Null

I am new to Moq and Mocks/Unit Testing in general. After watching a video on Mocking which uses Moq, I thought I had enough understanding to start setting up a few simple tests for a project I am working on. However, no amount of fiddling with the code helps my first test pass.
Here is the code I have:
Interface Being Tested
public interface IDataInterface
{
Task<IList<T>> GetData<T>(string url);
// Other stuff
}
Implementation of Interface Method GetData<T>
public async Task<IList<T>> GetData<T>(string url)
{
try
{
var json = await client.GetAsync(url).Result.Content.ReadAsStringAsync();
var data = (JObject)JsonConvert.DeserializeObject(json);
JArray arr = (JArray)data["resource"];
return arr.ToObject<IList<T>>();
}
catch (InvalidCastException icEx)
{
throw new InvalidCastException("An error occurred when retrieving the data", icEx);
}
// Other catches
}
Service Calling Implemented Interface GetData<T>
public async Task<IList<MyObj>> GetActiveObjs()
{
var data = await _myImplementedInterface.GetData<MyObj>(ActiveUrl);
return data;
}
My Test
[Fact]
public async void MyImplementedInterface_GetActive_ReturnsDataOrEmptyList()
{
var _activeUrl = "http://some.url";
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IDataInterface>()
.Setup(x => x.GetData<MyObj>(_activeUrl))
.Returns(Task.FromResult(_SomeStaticDataRepresentation)));
var svc = mock.Create<MyService>();
var expected = _SomeStaticDataRepresentation;
var actual = await svc.GetActiveObjs();
Assert.True(actual != null);
// Other assertions that never matter because of the null value of _actual_ variable
}
}
Early on, I had issues because the project uses Autofac and Moq, but I resolved those specific issues. However, I cannot seem to get past the null value coming back from the service call. When running the project, the method returns data, just as expected, so I am flummoxed as to where the issue lies. Reviewing various posts and the Moq Quickstart did not provide what I needed to solve this myself, so my hope is there is someone here who can tell me what I am doing wrong. I apologize already as I am certain it is a newbie mistake.
Addressing the implementation first. Avoid mixing async-await and blocking calls like Wait() and .Result which can result in deadlocks.
Reference Async/Await - Best Practices in Asynchronous Programming
public async Task<IList<T>> GetData<T>(string url) {
try {
var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
var data = (JObject)JsonConvert.DeserializeObject(json);
JArray arr = (JArray)data["resource"];
return arr.ToObject<IList<T>>();
} catch (InvalidCastException icEx) {
throw new InvalidCastException("An error occurred when retrieving the data", icEx);
}
// Other catches
}
For the subject method under test, if nothing needs to be awaited then there is no need to make the function async, just return the Task
public Task<IList<MyObj>> GetActiveObjs() {
return _myImplementedInterface.GetData<MyObj>(ActiveUrl);
}
Now for the test, since already using tasks, then the test should be async and the subject awaited as well.
[Fact]
public async Task MyImplementedInterface_GetActive_ReturnsDataOrEmptyList() {
using (var mock = AutoMock.GetLoose()) {
//Arrange
IList<MyObj> expected = _SomeStaticDataRepresentation;
mock.Mock<IDataInterface>()
.Setup(x => x.GetData<MyObj>(It.IsAny<string>()))
.ReturnAsync(expected);
var svc = mock.Create<MyService>();
//Act
var actual = await svc.GetActiveObjs();
//Assert
Assert.True(actual != null);
Assert.True(actual == expected);
// ...
}
}
Assuming, based on what was shown it is uncertain what the active URL would have been, it could be ignored in the test using It.IsAny<string>().

Calling Async in a Sync method

I've been reading examples for a long time now, but unfortunately I've been unable to apply the solutions to the code I'm working with. Some quick Facts/Assorted Info:
1) I'm new to C#
2) The code posted below is modified from Amazon Web Services (mostly stock)
3) Purpose of code is to compare server info to offline already downloaded info and create a list of need to download files. This snip is for the list made from the server side, only option with AWS is to call async, but I need this to finish before moving forward.
public void InitiateSearch()
{
UnityInitializer.AttachToGameObject(this.gameObject);
//these are the access key and secret access key for credentials
BasicAWSCredentials credentials = new BasicAWSCredentials("secret key", "very secret key");
AmazonS3Config S3Config = new AmazonS3Config()
{
ServiceURL = ("url"),
RegionEndpoint = RegionEndpoint.blahblah
};
//Setting the client to be used in the call below
AmazonS3Client Client = new AmazonS3Client(credentials, S3Config);
var request = new ListObjectsRequest()
{
BucketName = "thebucket"
};
Client.ListObjectsAsync(request, (responseObject) =>
{
if (responseObject.Exception == null)
{
responseObject.Response.S3Objects.ForEach((o) =>
{
int StartCut = o.Key.IndexOf(SearchType) - 11;
if (SearchType == o.Key.Substring(o.Key.IndexOf(SearchType), SearchType.Length))
{
if (ZipCode == o.Key.Substring(StartCut + 12 + SearchType.Length, 5))
{
AWSFileList.Add(o.Key + ", " + o.LastModified);
}
}
}
);
}
else
{
Debug.Log(responseObject.Exception);
}
});
}
I have no idea how to apply await to the Client.ListObjectsAsync line, I'm hoping you all can give me some guidance and let me keep my hair for a few more years.
You can either mark your method async and await it, or you can call .Wait() or .Result() on the Task you're given back.
I have no idea how to apply await to the Client.ListObjectsAsync line
You probably just put await in front of it:
await Client.ListObjectsAsync(request, (responseObject) => ...
As soon as you do this, Visual Studio will give you an error. Take a good look at the error message, because it tells you exactly what to do next (mark InitiateSearch with async and change its return type to Task):
public async Task InitiateSearchAsync()
(it's also a good idea to add an Async suffix to follow the common pattern).
Next, you'd add an await everywhere that InitiateSearchAsync is called, and so on.
I'm assuming Client.ListObjectsAsync returns a Task object, so a solution for your specific problem would be this:
public async void InitiateSearch()
{
//code
var collection = await Client.ListObjectsAsync(request, (responseObject) =>
{
//code
});
foreach (var item in collection)
{
//do stuff with item
}
}
the variable result will now be filled with the objects. You may want to set the return type of InitiateSearch() to Task, so you can await it too.
await InitiateSearch(); //like this
If this method is an event handler of some sort (like called by the click of a button), then you can keep using void as return type.
A simple introduction from an unpublished part of the documentation for async-await:
Three things are needed to use async-await:
The Task object: This object is returned by a method which is executed asynchronous. It allows you to control the execution of the method.
The await keyword: "Awaits" a Task. Put this keyword before the Task to asynchronously wait for it to finish
The async keyword: All methods which use the await keyword have to be marked as async
A small example which demonstrates the usage of this keywords
public async Task DoStuffAsync()
{
var result = await DownloadFromWebpageAsync(); //calls method and waits till execution finished
var task = WriteTextAsync(#"temp.txt", result); //starts saving the string to a file, continues execution right await
Debug.Write("this is executed parallel with WriteTextAsync!"); //executed parallel with WriteTextAsync!
await task; //wait for WriteTextAsync to finish execution
}
private async Task<string> DownloadFromWebpageAsync()
{
using (var client = new WebClient())
{
return await client.DownloadStringTaskAsync(new Uri("http://stackoverflow.com"));
}
}
private async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath, FileMode.Append))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
}
Some thing to note:
You can specify a return value from an asynchronous operations with Task. The await keyword waits till the execution of the method finishes, and returns the string.
the Task object contains the status of the execution of the method, it can be used as any other variable.
if an exception is thrown (for example by the WebClient) it bubbles up at the first time the await keyword is used (in this example at the line string result (...))
It is recommended to name methods which return the Task object as MethodNameAsync
For more information about this take a look at http://blog.stephencleary.com/2012/02/async-and-await.html.

callback based async method with multiple parameters to awaitabletask

I have the following code to connect to MYOB's SDK
var cfsCloud = new CompanyFileService(_configurationCloud, null, _oAuthKeyService);
cfsCloud.GetRange(OnComplete, OnError);
where
private void OnComplete(HttpStatusCode statusCode, CompanyFile[] companyFiles)
{ // ask for credentials etc }
I want to convert this to use a TaskCompletionSource
like this example
however my OnComplete has multiple parameters.
How do I code that?
As mentioned in the comment
The SDK for Accountright API supports async/await i.e. GetRangeAsync
so you can do something like this if you wanted/needed to wrap it in a TaskCompletionSource
static Task<CompanyFile[]> DoWork()
{
var tcs = new TaskCompletionSource<CompanyFile[]>();
Task.Run(async () =>
{
var cfsCloud = new CompanyFileService(_configurationCloud, null, _oAuthKeyService);
var files = await cfsCloud.GetRangeAsync();
tcs.SetResult(files);
});
return tcs.Task;
}

Parallel.ForEach and async-await [duplicate]

This question already has answers here:
Nesting await in Parallel.ForEach [duplicate]
(11 answers)
Closed last year.
I had such method:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
foreach(var method in Methods)
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
}
return result;
}
Then I decided to use Parallel.ForEach:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
Parallel.ForEach(Methods, async method =>
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
});
return result;
}
But now I've got an error:
An asynchronous module or handler completed while an asynchronous operation was still pending.
async doesn't work well with ForEach. In particular, your async lambda is being converted to an async void method. There are a number of reasons to avoid async void (as I describe in an MSDN article); one of them is that you can't easily detect when the async lambda has completed. ASP.NET will see your code return without completing the async void method and (appropriately) throw an exception.
What you probably want to do is process the data concurrently, just not in parallel. Parallel code should almost never be used on ASP.NET. Here's what the code would look like with asynchronous concurrent processing:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
var tasks = Methods.Select(method => ProcessAsync(method)).ToArray();
string[] json = await Task.WhenAll(tasks);
result.Prop1 = PopulateProp1(json[0]);
...
return result;
}
.NET 6 finally added Parallel.ForEachAsync, a way to schedule asynchronous work that allows you to control the degree of parallelism:
var urlsToDownload = new []
{
"https://dotnet.microsoft.com",
"https://www.microsoft.com",
"https://twitter.com/shahabfar"
};
var client = new HttpClient();
var options = new ParallelOptions { MaxDegreeOfParallelism = 2 };
await Parallel.ForEachAsync(urlsToDownload, options, async (url, token) =>
{
var targetPath = Path.Combine(Path.GetTempPath(), "http_cache", url);
var response = await client.GetAsync(url, token);
// The request will be canceled in case of an error in another URL.
if (response.IsSuccessStatusCode)
{
using var target = File.OpenWrite(targetPath);
await response.Content.CopyToAsync(target);
}
});
Alternatively, with the AsyncEnumerator NuGet Package you can do this:
using System.Collections.Async;
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
await Methods.ParallelForEachAsync(async method =>
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
}, maxDegreeOfParallelism: 10);
return result;
}
where ParallelForEachAsync is an extension method.
Ahh, okay. I think I know what's going on now. async method => an "async void" which is "fire and forget" (not recommended for anything other than event handlers). This means the caller cannot know when it is completed... So, GetResult returns while the operation is still running. Although the technical details of my first answer are incorrect, the result is the same here: that GetResult is returning while the operations started by ForEach are still running. The only thing you could really do is not await on Process (so that the lambda is no longer async) and wait for Process to complete each iteration. But, that will use at least one thread pool thread to do that and thus stress the pool slightly--likely making use of ForEach pointless. I would simply not use Parallel.ForEach...

How to get data (asynchronously) from WCF?

I have got the code that using WCF, requests data from the server.
For Example:
public static Company LoadCompanyInfo(Guid session)
{
var client = new QualerServiceClient("QualerService");
return client.GetCompanyInfo(session);
}
I need to make my wpf application to run these code asynchronously.
I try:
public static Company LoadCompanyInfoAsync(Guid session)
{
var client = new QualerServiceClient("QualerService");
client.BeginGetCompanyInfo(session, new AsyncCallback(EndLoadCompanyInfoAsync), client);
// How to Get Data from AsyncCallback function?
return null;
}
private static void EndLoadCompanyInfoAsync(IAsyncResult r)
{
var client = r.AsyncState as QualerServiceClient;
var result = client.EndGetCompanyInfo(r);
// how to return the result value ??
}
But I don't know how to return data from callback function.
I have got methods:
BeginGetCompanyInfo and EndGetCompanyInfo
GetCompanyInfoAsync
and event:
GetCompanyInfoCompleted.
Quastions:
How can I get the data from the callback method?
What is the difference between GetCompanyInfoAsync and Begin\End?
Best Practices: How can execute a method asynchronously, so that the GUI of my WPF App is not freezes?
I'm assuming that you're using VS2012.
First, if your target is .NET 4.0, then install (via NuGet) the Async Targeting pack. If your target is .NET 4.5, you don't have to do anything special.
Next, re-create your client proxy. The existing Begin/End/Async endpoints will be replaced by a single Task<Company> GetCompanyInfoAsync(Guid).
Now you can use it like this:
public static Task<Company> LoadCompanyInfoAsync(Guid session)
{
var client = new QualerServiceClient("QualerService");
return client.GetCompanyInfoAsync(session);
}
public async void ButtonClickOrWhatever(...)
{
var company = await LoadCompanyInfoAsync(mySession);
// Update UI with company info.
}
The old Begin/End method pair was using the Asynchronous Programming Model (APM). The old Async/event pair was using the Event-based Asynchronous Programming model (EAP). The new Async method is using the Task-based Asynchronous Programming model (TAP). I have more information on async WCF on my blog.
You could use the async CTP for .net 4, which will become part of .net in 5.
It adds two new keywords into C# the async and await keywords.
You mark a method or lamda with the async keyword and return a
Task or Task<T>
when you call your method you would call it like so
var result = await LoadCompanyInfo(sessionId);
Async CTP
public static async Task<Company> LoadCompanyInfo(Guid session)
{
Company result = default(Company);
await TaskEx.Run(()=>{
var client = new QualerServiceClient("QualerService");
result = client.GetCompanyInfo(session);
});
return result;
}
Use TPL:
Task t = TaskFactory.FromAsync(
beginMethod: BeginGetCompanyInfo,
endMethod: EndGetCompanyInfo,
arg1: session,
state: null);
t.ContinueWith(result =>
{
// handle result
});

Categories

Resources