Call async WCF service when issuing loans

I have a WCF service running on a server that is configured to accept Kerberos authentication.

Kerberos works great, so the WCF service knows which user is connecting to it. The service offers everything as Async methods. Like this here (just an example for clarity).

public ExampleService : IExampleService { public Task<string> GetUsernameAsync() { return await Task.Run(() => System.Threading.Thread.CurrentPrincipal.Name); } } 

On the client side, I have a controller (this is an MVC page, but it does not matter) that calls methods asynchronously.

 public ExampleController { public async Task<ActionResult> Index() { using(var serviceClient = ServiceFactory.GetServiceClient()) using(Security.Impersonation.Impersonate()) { var data = await serviceClient.GetUsernameAsync(); return View(data); } } } 

Ignoring works fine if I don't use it.

Since Task<> does not convey impersonal identity, I would like to know if there is any possibility to change the executing Task user or do something else to make the impersonation work in this use - the thing.

I tried custom awaiter (how it can be done with culture in this case), but it doesn’t work at all (well, it’s just not impersonating).

+6
source share
3 answers

Good - after more in-depth research, I finally found a solution on how to pass the given window identifiers in asynchronous tasks.

The solution is a machine solution and will be installed for all (in this case) 64-bit ASP.NET 4.5 applications.

Locate the aspnet.config file in C:\Windows\Microsoft.Net\Framework64\v4.0.30319 (perhaps this applies to later versions as well) and change the value of legacyImpersonationPolicy to false

 <legacyImpersonationPolicy enabled="false"/> 

Be sure to restart IIS (or restart the computer).
This then causes the impersonation to flow while you use managed methods to impersonate. In my case, I personify something like this, which works great:

 class Impersonation : IDisposable { public static Impersonation Impersonate() { return new Impersonation(); } private WindowsImpersonationContext ImpersonationContext { get; set; } private Impersonation() { var currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity as WindowsIdentity; if (currentIdentity != null && currentIdentity.IsAuthenticated) { ImpersonationContext = currentIdentity.Impersonate(); return; } throw new SecurityException("Could not impersonate user identity"); } public void Dispose() { if(ImpersonationContext != null) ImpersonationContext.Dispose(); } } } 

In the aspnet.config settings (btw. It doesn’t work to install it in the web.config file) it is explained here: http://msdn.microsoft.com/en-us/library/ms229296(v=vs.110).aspx (basically it says, if so, we do it in the way of .NET 1.1)

You can check if Windows authentication is performed or not using this method:

 System.Security.SecurityContext.IsWindowsIdentityFlowSuppressed() 
+5
source

I do not agree with your question.

The problem is not your await . But your Task.Run . Actually there should not be await Task.Run for you ASP.Net code. The effect of this is an unnecessary thread switch. Since you do not have STA threads in ASP.Net, there is no need for this, and it just slows down your code.

If you stick to real threads without Task , you shouldn't have any problems, as you will remain in one thread. If your application server does not have a very limited number of clients and has a huge number of processor-bound operations, multithreading is bad for scaling, since one user can quickly fill out your server’s schedule.

You really should use Task.FromResult or TaskCompletionSource.Task to make sure that you remain single-threaded. Which, by the way, will fix your problem using the [ThreadLocal] properties.

TL: DR

Do not use Task.Run on your server side. Use Task.FromResult so that you have only one thread.

EDIT: answer

Which stream? On the client side, you will still use await . I never said do not use await . I said that DO NOT use await directly with Task.Run (except for the UI thread). I did not say that you should LOCK the thread. Since your thread must do WORK to get the result you pass to Task.FromResult . LOCK means that the thread does nothing, consuming resources (namely, memory). Damn it doesn't even have to

The server side should use this template:

 public ExampleService : IExampleService { public Task<string> GetUsernameAsync() { var name = System.Threading.Thread.CurrentPrincipal.Name; return Task.FromResult(name); } } 

customer must stay

 public ExampleController { public async Task<ActionResult> Index() { using(var serviceClient = ServiceFactory.GetServiceClient()) using(Security.Impersonation.Impersonate()) { var data = await serviceClient.GetUsernameAsync(); return View(data); } } } 

and in the case when your ServiceClient is resolved locally, everything is done synchronously (faster and with less resources). The point here is that you are using the Task async pattern for the Thread Style in async. Task.Run is aync concurrency style and should be used only when you need to use a different thread (either because you are attached to the processor, or ONLY THESE NEEDS that will be used for something else).

+3
source

Since I am responsible for WCF interfaces, there is one solution here that works (but which I don't like, as it is more or less duplication of code):

 [ServiceContract] interface IExampleService { [OperationContract] string GetUsername(); } interface IExampleServiceAsync { Task<string> GetUserNameAsync(); } class ExampleService : IExampleService { public string GetUsername() { return System.Threading.Thread.CurrentPrincipal.Name; } } class ExpampleServiceClient : ServiceClient<IExampleService>, IExampleServiceAsync { public Task<string> GetUsernameAsync() { return Task.Run(() => GetUsername()); } private string GetUsername() { using(Security.Impersonation.Impersonate()) { return base.Proxy.GetUsername(); } } } 

I have to say that this is a workaround, not a solution, and it changes the server-side interfaces (only for non-asynchronous interfaces), but at least it works.

One plus for this solution is that you can implement impersonation as a behavior pattern on top of the ExampleServiceClient class.

0
source

All Articles