I'm having some problems converting this method from c# to VB, it's working flawless in C# :
private async void Test()
{
DataSet dt;
var client = new xxxSoapClient();
dt = await client.ToDoAsync();
}
I'm using Async/await in VS 2012, and in c# it's all ok, but when trying to do exactly the same in VB it returns an error indicating that system.void is not awaitable!!!
Private Async Sub Test()
Dim dt As DataTable
Dim Client As New xxxSoapClient
dt = Await Client.ToDoAsync()
End Sub
The webservice is just returning a simple datatable, ideas someone?
The WCF proxy generator before VS2012 would generate *Async methods that returned void and signaled their completion using events. As of VS2012, the WCF proxy generator by default will generate *Async methods that return Task<T>.
Try re-generating the proxy.
If that doesn't work, check your "advanced" options for the style of asynchronous methods to create. There are three styles: Asynchronous Programming Model (APM) uses Begin*/End*/IAsyncResult; Event-based Asynchronous Pattern (EAP) uses *Async/*Completed/AsyncCompletedEventArgs; Task-based Asynchronous Pattern (TAP) uses *Async/Task.
TAP works naturally with async/await, so that's the one you want.
Related
To better explain what I would like to do in Asp.NET 4.5, I'll give an example of how I've gotten this to work in .NET Core.
In .NET Core, if you want all the code for a request to use a single object that gets disposed of if an Exception is thrown, you can create a middleware with the app.Use() method in the Startup class like the following:
app.Use(async delegate (HttpContext Context, Func<Task> Next)
{
using (var TheStream = new MemoryStream())
{
//the statement "await Next();" lets other middlewares run while the MemoryStream is alive.
//if an Exception is thrown while the other middlewares are being run,
//then the MemoryStream will be properly disposed
await Next();
}
});
How can I do something like this in .NET 4.5? I was thinking of using the Global.asax.cs but I would have to span the using { ... } statement across all the various events (Application_Start, Application_AuthenticateRequest, etc), which I don't believe is possible.
I was thinking of using the Global.asax.cs
Yes, using some pair of events like HttpApplication.BeginRequest with HttpApplication.EndRequest is the way to do this on ASP.NET pre-Core.
but I would have to span the using { ... } statement across all the various events
Yes-ish. What you need to do is split the using logic across those events. E.g., in the BeginRequest event, do the new MemoryStream() and store it in the request context. Then in the EndRequest event, retrieve the MemoryStream from the request context and call Dispose.
I am trying to create a system that synchronizes between two other systems' data.
I work on ASP.NET Web Forms using VB (Cannot be changed)
The main system functions will be in a form of Web API which will be triggered by a scheduled task or other events, such as a website form or a landing page.
Each of these functions call a REST API of System 1 and the REST API of System 2 , operates the data, and then calls each system REST APIs to update both sides.
I chose to use a ASP.NET Web Api 2 for the main system, and HttpClient to call the functions.
There will be hundreds of thousands of transactions per day. It is a lot! So I chose to use async/await methods for the HttpClient, (because of the many simultaneous long processing requests), but ASP.NET seems to have forced me to convert all the functions from bottom to top, including the Web Api functions and the database access to Async!
So I ended up changing all the functions to Async and in all the functions that call them I use Await for everything.
Everything seems to work. I don't know if what I did is correct, and I see there is no way to check if my functions are actually working asynchronically.
About the ConfigureAwait(False) I added it because I don't have operations that are context related. If there will be I will remove this statement. I read it is recommended to use it when it is possible. (Am I right?)
SMALL COMMENT:
Why is my solution good??? I am trying to avoid blocking the main thread by creating much more worker threads. Why is this a better solution? I am creating a lot of awaits which each one starts a worker. Isn't it a worse practice than the synchronic solution????
Can somebody tell me if what I am doing is correct and if not - please explain why or if there are other approaches to this scenario?
Here is the code for example (only the relevant parts). A little explanation of what you see:
The WebApi Controller has an Login function
The Login function calls the System1.DoSomething asynchronically
The System1.DoSomething calls the private function
System1.SetCredentials asynchronically
The System1.DoSomething also uses HttpHandler to get data
asynchronically from System1's API
System1.SetCredentials function calls MyLoginManager.GetCredentials asynchronically
MyLoginManager.GetCredentials calls the database asynchronically using DBHelper.ExecuteReaderAsync
The DBHelper.ExecuteReaderAsync function calls ExecuteReaderAsync
asynchronically and also opens the connection asynchronically using
OpenAsync() function
The WebAPI Controller
Public Class WebApiController
Inherits ApiController
Public Async Function Login() As Threading.Tasks.Task(Of IHttpActionResult)
Dim result As MyResult= Await System1.DoSomething().ConfigureAwait(False)
End Function
The System1 Class
Public Class System1
Public Shared Async Function DoSomething() As Task(Of MyResult)
Try
Using client As New HttpClient
client.BaseAddress = New Uri("blablabla")
Await SetCredentials(client).ConfigureAwait(False)
Dim response As HttpResponseMessage = Await client.GetAsync(urlParameters).ConfigureAwait(False)
... More code
End Using
Catch ex As Exception
End Try
End Function
Private Shared Async Function SetCredentials(client As HttpClient) As Task
Dim auth As BasicAuthenticationData = Await MyLoginManager.GetCredentials.ConfigureAwait(False)
Dim credentials As String = Cryptography.EncodeBase64(String.Format("{0}\{1}:{2}", auth.userName, auth.userPassword))
client.DefaultRequestHeaders.Add("Authorization", "Basic " & credentials)
... More code
End Function
End Class
The MyLoginManager Class
Public Class MyLoginManager
Public Shared Async Function GetCredentials() As Threading.Tasks.Task(Of BasicAuthenticationData)
Dim auth As New BasicAuthenticationData
Dim dbConn As String = DBConnection.GetConnection(True)
Dim q As String = "SELECT * FROM BlaBlaBla"
Using sdr As SqlDataReader = Await DBHelper.ExecuteReaderAsync(dbConn, q, Nothing).ConfigureAwait(False)
... More code
End Using
Return auth
End Function
End Class
The DBHelper Class
Public Class DBHelper
Public Shared Async Function ExecuteReaderAsync(ByVal dbConnection As String, ByVal commandText As String, ByVal params() As SqlParameter) As Threading.Tasks.Task(Of SqlDataReader)
Dim dbConnectionAsync As String = New SqlConnectionStringBuilder(dbConnection) With {
.AsynchronousProcessing = True
}.ToString
Dim objConn As New SqlConnection(dbConnectionAsync)
Dim oc As New SqlCommand(commandText, objConn)
Dim sdr As SqlDataReader
' Throws a custom exception if there is a problem
Try
Await oc.Connection.OpenAsync.ConfigureAwait(False)
sdr = Await oc.ExecuteReaderAsync(CommandBehavior.CloseConnection).ConfigureAwait(False)
Return sdr
Catch ex As Exception
End Try
End Function
End Class
You should add a call to ConfigureAwait(false) to any await behind any await that comes out of any controller action.
As Mister Epic said you'll loose things like HttpContext.Current if you call ConfigureAwait(false) and you shouldn't do that on controller action methods. But that also means that every time you don't you incur in context switching.
What you should do is extract the logic in controller action methods to their own methods (preferably on their own class) and pass every thing they need to do their work.
So, the only thing you did wrong was to call ConfigureAwait(false) in the controller action method.
Don't add ConfigureAwait in your web api project. Use it in library code.
The big gotcha is that when you call a method that uses ConfigureAwait, you'll lose your context. Your context includes important details like your session, so you'll need to ensure you capture any details from HttpContext you need before you call into library code that uses ConfigureAwait.
I have developed a WCF in ASP.NET 4.5 with a couple of simple methods. One such method has a return type of bool (written in c#). When I add this service to my ASP.NET 4.5 web application as a Service Reference, it works as expected in the code behind. It also works the same way in a .NET 4.5 C# Console application. Below is the code in the Implementation file for this method:
public bool AddADUser(string a, string b)
{
bool done = false;
return done;
}
When I call it from my programs, it looks like this:
static void Main(string[] args)
{
var proxy = new ServiceReference1.ADServiceClient();
proxy.Open();
try
{
Console.WriteLine(proxy.HelloWorld());
bool success = proxy.AddADUser("testA", "testB");
Console.WriteLine(success.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException);
}
finally
{
proxy.Close();
}
}
This is how it works in my ASP.NET 4.5 / C# app, and my C# .NET 4.5 Console App.
When I add this as a "Web Reference" to an existing ASP.NET 2.0 / VB.NET app, it does something different. The command to call the AddADUser() function is all of a sudden requiring 4 parameters:
AddADUser(a As String, b As String, ByRef AddADUserResult As Boolean, ByRef AddADUserResultSpecified As Boolean)
Why are these parameters being added -- is this something with VB.NET not allowing this to actually return a boolean, or a web reference not being able to return a boolean, or a problem with this being ASP.NET 2.0 ?
Or do I need to make a custom DataContract? I have that part left out of my Interface, just relying on defaults. Do I need to specify XmlSerializer somewhere also to be able to use this? It appears to actually do what it is supposed to, and I just can't figure out why there are two booleans and which one is the one I want.
This page gives a long explanation about it and a weird workaround that I didn't feel like doing:
http://www.codeproject.com/Articles/323097/WCF-ASMX-Interoperability-Removing-the-Annoying-xx
What I wound up doing was adding
[OperationContract, XmlSerializerFormat(Style = OperationFormatStyle.Rpc)]
to my methods and I also added
[ServiceContract,XmlSerializerFormat]
to my interface attribute and now they act like I would expect.
Reference: http://www.wenda.io/questions/1191041/result-and-resultspecified-parameters-in-wcf-service.html
Is it possible to combine upshot/knockout with signalr (I can only find questions about knockout and signalr only)?
For example if I add a Task using:
self.addTask = function () {
var task = new Task({
LastUpdated : new Date().toMSJSON(),
Title : this.newTaskText(),
IsDone : true
});
self.tasks.unshift(task);
}
in the view model, this will add it to the view automatically (based on the knockout data binding) and call:
public void InsertTask(Task task)
{
InsertEntity(task);
}
in the server. What if I also want to broadcast this to other clients.. is it possible using the same libraries? If it is.. what changes should I have to do / additional things I need to do? Are there any alternatives that will make this easier but still following the upcoming Microsoft ASP.NET MVC 4 stack?
You should be able to, On the server you can call
var connection = AspNetHost.DependencyResolver.Resolve<IConnectionManager().GetConnection<MyConnection>();
connection.Broadcast("Called from an mvc controller or server side method");
Or you could create a hub and implement it client side in the function:
self.addTask
to send a "addTask" message to clients.
I have the following assemblies in my ASP.NET app:
Website - this is an ASP.NET website
ClassLib - this is just a class lib that contains all the business logic
Class Lib needs to interact with the HttpContext Session and Request objects. This is a code upgrade from an old ASP app, where I've hoovered all the VBScript that contained the logic and put it into VB.NET. We simply didn't have time to rewrite.
Instead of ClassLib interacting directly with HttpContext, which I thought was BAD and also prevented us from unit testing, I introduced the following abstraction layer:
Public Class Request
Private Shared _requestWrapper as IRequestWrapper
Public Shared ReadOnly Property RequestWrapper()
Get
If _requestWrapper Is Nothing Then
Throw New Exception("_requestWrapper is null. Make sure InitRequest() is called with valid parameters")
End If
Return _requestWrapper
End Get
End Property
Public Shared Sub InitRequest(ByRef requestWrapper As IRequestWrapper)
_requestWrapper = requestWrapper
End Sub
Public Shared Function GetVal(ByVal key As String) As Object
Return RequestWrapper.GetVal(key)
End Function
etc.
This means in the unit tests I can supply my own MockRequest object into this Request class, which is just a simple NameValue collection. The code in the ClassLib and the Website then simply use the Request class and are none the wiser that it isn't coming from the HttpContext, but rather this mock class.
When it comes to the real deal, I simply have the following (C#) class:
public class RealRequest : IRequestWrapper
{
public void Initialize(HttpContext context)
{
}
#region Implementation of IRequestWrapper
public object GetVal(string index)
{
return HttpContext.Current.Request[index];
}
etc.
This is initialised in Session_Start of global.asax in the Website, as follows:
protected void Session_Start(object sender, EventArgs e)
{
IRequestWrapper requestWrapper = new RealRequest();
WebSession.Request.InitRequest(ref requestWrapper);
}
I think this is similar to the Static Gateway pattern.
Now, I am aware of singletons and static vars in a multi threaded environment such as ASP.NET, but this is slightly different. When it gets down to the RequestWrapper.GetVal(), its actually going to the HttpContext for that running thread - and pulling the value from that.
Certainly, any concurrent tests that we do with multiple users hitting the same server have never shown up any strange behaviour.
I'm just looking for re-assurance that this is a sound design, and if not why not?
Thanks
Duncan
This is fine. We have a very similar case in our applications that either uses HttpContext if it exists or fake implementations otherwise.
The one thing to watch out for is that there is a very specific instance where HttpContext.Current will return a value but HttpContext.Current.Request will throw an exception when triggered by the Application_Start event. In framework code, you really don't know (or want to know) what triggered the call though.
Workaround for HttpContext.HideRequestResponse being internal? Detect if HttpContext.Request is really available?