Debugger skipping methods after organizing code into new solutions - c#

I had a perfectly working API that was making http calls & a UI that was using that API.
Everything was working and it was built really ugly ( 2 solutions for everything), so I wanted to separate everything so it would be more organized.
UI
DataManagerService
DataManager
Contracts
After a lot of copy paste & dependencies references it all looked like its working with 0 errors.
BUT now something weird happens, A method is being skipped and I have NO IDEA WHY.
I am not on release mode.
If anyone has any ideas I would appreciate it!
The method that is being skipped :
private static List<Actor> ReadActorsFromJson(string json)
{
List<Actor> celebListReadFromFile;
try
{
var celebJson = File.ReadAllText(json);
celebListReadFromFile = JsonConvert.DeserializeObject<List<Actor>>(celebJson);
}
catch (Exception ex)
{
celebListReadFromFile = new List<Actor>();
// Empty list/whatever it got in it
}
return celebListReadFromFile;
}
Which is being invoked by :
public static async Task SaveOriginal()
{
foreach (var currceleb in ReadActorsFromJson(filePath))
{
var curr = currceleb;
originalList.TryAdd(currceleb.name, currceleb);
}
}
and this method is being invoked by the classes static constructor:
static Logic()
{
originalList = new ConcurrentDictionary<string, Actor>();
filePath = ConfigurationManager.AppSettings["tempList"];
File.Copy(filePath, BACKUP, true);
// invoking the method
SaveOriginal();
}
The API:
using Contracts;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace WebApplication12.Controllers
{
public class ValuesController : Controller
{
public ILogic _Ilogic;
public ValuesController(ILogic logic)
{
_Ilogic = logic;
}
// GET api/values
public async Task<ActionResult> GetActors()
{
return Json(await _Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
public async Task<ActionResult> RemoveActorAsync(Actor actor) {
await _Ilogic.RemoveActorAsync(actor.name);
return Json(await _Ilogic.GetAllActorsAsync());
}
public async Task<ActionResult> ResetAsync()
{
await _Ilogic.ResetAsync();
return Json(await _Ilogic.GetAllActorsAsync());
}
}
}
The business logic :
using System;
using System.Collections.Generic;
using System.IO;
using System.Configuration;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq;
using Newtonsoft.Json;
using Contracts;
namespace DataManager
{
public class Logic : ILogic
{
static string filePath;
private static ConcurrentDictionary<string, Actor> originalList;
const string BACKUP = #"C:\tempList\backup.txt";
static Logic()
{
originalList = new ConcurrentDictionary<string, Actor>();
filePath = ConfigurationManager.AppSettings["tempList"];
File.Copy(filePath, BACKUP, true);
SaveOriginal();
}
public async static Task<List<Actor>> GetCelebritiesInner()
{
return originalList.Values.ToList();
}
public async Task<List<Actor>> GetAllActorsAsync()
{
return await GetCelebritiesInner();
}
// Try to read the data from the Json and initialize it. if failed , initialize with whatever it got. return
private static List<Actor> ReadActorsFromJson(string json)
{
List<Actor> celebListReadFromFile;
try
{
var celebJson = File.ReadAllText(json);
celebListReadFromFile = JsonConvert.DeserializeObject<List<Actor>>(celebJson);
}
catch (Exception ex)
{
celebListReadFromFile = new List<Actor>();
// Empty list/whatever it got in it
}
return celebListReadFromFile;
}
public async Task RemoveActorAsync(string name)
{
if (originalList.TryRemove(name, out Actor removedActor))
{
var jsonToWrite = JsonConvert.SerializeObject(await GetCelebritiesInner());
try
{
File.WriteAllText(filePath, jsonToWrite);
}
catch (Exception ex)
{
//Unable to remove due to an error.
}
}
}
public async Task ResetAsync()
{
originalList.Clear();
await UpdateFile();
await SaveOriginal();
}
//Saving the actor, adding the name as key & object as value.
public static async Task SaveOriginal()
{
foreach (var currceleb in ReadActorsFromJson(filePath))
{
var curr = currceleb;
originalList.TryAdd(currceleb.name, currceleb);
}
}
public static async Task UpdateFile()
{
File.Copy(BACKUP, filePath, true);
}
}
}
When running the program, the static ctor is being invoked and should invoke the SaveOriginal method. which it doesn't.

Static constructor calls when the first access is made. You are using dependency injection which is lazy loading. It doesn't create object until first access is made.
So, Try to get/set any property or method, static constructor will be called first.

Ok so I cleaned and re built every solution one by one ( I don't know if it helped) & then I ran the API, sent a request from POSTMAN instead of opening the UI, in postman I got the following error:
Could not load file or assembly 'Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies
I looked at the versions in the Nuget packages and there was no 12.0.0.0 in there, so I removed Newtonsoft.Json from all solutions, re-installed Newtonsoft.Json in every solution and it worked.
turns out somehow when opening the new solutions, I installed different Newtonsoft.Json versions. and this caused the program to skip the method without giving the stack trace like postman did, weird.

Related

Code sample not compiling

I have been trying to use some sample code provided by Microsoft. I
Downloaded the file
Hit unblock on the file
Unzipped the file
Clicked on the solution called QuizGame sample
The solution opened in Visual Studio 2015
The solution automatically registered hundreds of errors
I opened the C# files in the solution explorer to see what was going on and each C# file had tons of errors. Each error was some how related to the System reference.
Error CS0246 The type or namespace name 'System' could not be found
(are you missing a using directive or an assembly reference?)
The warning was
Warning Cannot resolve Assembly or Windows Metadata file 'System.Runtime.dll'
It also shows all the System imports with red lines underneath them. It sounds like it is not recognizing the System reference.
Here is the code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Networking.Sockets;
namespace P2PHelper
{
public class P2PSessionHost : P2PSession, IDisposable
{
private Dictionary<Guid, P2PClient> ClientMap { get; set; }
private StreamSocketListener SessionListener { get; set; }
private Timer Timer { get; set; }
public P2PSessionHost(P2PSessionConfigurationData config) : base(config)
{
this.SessionListener = new StreamSocketListener();
this.ClientMap = new Dictionary<Guid, P2PClient>();
}
public void Dispose()
{
this.SessionListener.Dispose();
this.SessionListener = null;
}
public async Task<bool> CreateP2PSession(SessionType type)
{
if (this.SessionListener == null) return false;
if (type != SessionType.LocalNetwork) throw new NotSupportedException(
"SessionType.LocalNetwork is the only SessionType supported.");
this.SessionHost = true;
this.SessionListener.ConnectionReceived += async (s, e) => await OnConnectionReceived(e.Socket);
await this.SessionListener.BindEndpointAsync(null, Settings.tcpPort);
this.InitializeNetworkInfo();
return await this.InitializeMulticast(null);
}
public bool RemoveClient(Guid clientID)
{
return this.ClientMap.Remove(clientID);
}
private bool AcceptingConnections { get; set; }
public void StartAcceptingConnections()
{
AcceptingConnections = true;
this.Timer = new Timer(async state => await SendMulticastMessage(""), null, 0, 500);
}
public void StopAcceptingConnections()
{
AcceptingConnections = false;
this.Timer.Dispose();
}
private async Task OnConnectionReceived(StreamSocket socket)
{
byte[] message = await RetrieveMessage(socket);
var newClient = new P2PClient { clientTcpIP = socket.Information.RemoteAddress.ToString() };
if (AcceptingConnections)
{
if (GetGuid(newClient).ToString() == (new Guid()).ToString())
{
Guid newGuid = Guid.NewGuid();
this.ClientMap.Add(newGuid, newClient);
this.OnConnectionComplete(newGuid);
}
}
this.OnMessageReceived(message, GetGuid(newClient));
}
private Guid GetGuid(P2PClient client)
{
return this.ClientMap.FirstOrDefault(
kvp => kvp.Value.clientTcpIP == client.clientTcpIP).Key;
}
protected async Task SendMulticastMessage(string output)
{
using (var multicastOutput = await this.MulticastSocket.GetOutputStreamAsync(
new Windows.Networking.HostName(Settings.multicastIP),
this.MulticastSocket.Information.LocalPort))
{
await multicastOutput.WriteAsync(Encoding.UTF8.GetBytes(output).AsBuffer());
}
}
public async Task<bool> SendMessage(Guid clientID, object message, Type type = null)
{
P2PClient client;
if (this.ClientMap.TryGetValue(clientID, out client))
{
return await base.SendMessage(message, client.clientTcpIP, Settings.tcpPort, type ?? typeof(object));
}
return false;
}
public async Task<bool> SendMessageToAll(object message, Type type = null)
{
var messageTasks = this.ClientMap.Keys.Select(guid => this.SendMessage(guid, message, type));
// When all the tasks complete, return true if they all succeeded.
return (await Task.WhenAll(messageTasks)).All(value => { return value; });
}
}
}
Not recognizing .NET references and namespaces like System.Generics, System, etc, usualy caused by compiling in Client Profile or referencing DLLs that are compiled using different versions of .NET.
Go to the project settings and validate you are compiling to the right version of .NET with no Client Profile turned on.

Using webbackgrounder nuget in MVC to run background task for long time

I need to implement a task in background so what is my task? I have a table that stores the rent amount of each customers, so I need to calculate the rent price in each month after a specific datetimeackf so I googled it and I found a piece of code that (it is nuget called webbackgrounder) I added it to my solution and it gives me this part of code to handle my task:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace WebBackgrounder.DemoWeb
{
public class SampleJob : Job
{
public SampleJob(TimeSpan interval, TimeSpan timeout)
: base("Sample Job", interval, timeout)
{
}
public override Task Execute()
{
return new Task(() => Thread.Sleep(3000));
}
}
}
I want to know how can I program my task ?
More details : Here
I found this article but in fact I don't know can I use this method for longtime ??
Best regards .
any ideas will be appreciated.
You need to also add in a class to the App_Start folder of your application that will start the Job and manage it's lifetime. You can see an example here... https://github.com/NuGet/WebBackgrounder/tree/master/src/WebBackgrounder.DemoWeb
Here is the code from the demo app
using System;
using Elmah;
using WebBackgrounder.Jobs;
[assembly: WebActivator.PostApplicationStartMethod(typeof(WebBackgrounder.DemoWeb.App_Start.WebBackgrounderSetup), "Start")]
[assembly: WebActivator.ApplicationShutdownMethod(typeof(WebBackgrounder.DemoWeb.App_Start.WebBackgrounderSetup), "Shutdown")]
namespace WebBackgrounder.DemoWeb.App_Start
{
public static class WebBackgrounderSetup
{
static readonly JobManager _jobManager = CreateJobWorkersManager();
public static void Start()
{
_jobManager.Start();
}
public static void Shutdown()
{
_jobManager.Dispose();
}
private static JobManager CreateJobWorkersManager()
{
var jobs = new IJob[]
{
new SampleJob(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20)),
/* new ExceptionJob(TimeSpan.FromSeconds(15)), */
new WorkItemCleanupJob(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(5), new WorkItemsContext())
};
var coordinator = new WebFarmJobCoordinator(new EntityWorkItemRepository(() => new WorkItemsContext()));
var manager = new JobManager(jobs, coordinator);
manager.Fail(ex => Elmah.ErrorLog.GetDefault(null).Log(new Error(ex)));
return manager;
}
}
}
However I found it simpler to just use the parts of Webbackgrounder that I needed as follows. Place this class in the App_Start folder
using System;
using BombaySapphireCds.Jobs;
using Elmah;
[assembly: WebActivator.PostApplicationStartMethod(typeof(BombaySapphireCds.App_Start.PodMonitorConfig), "Start")]
[assembly: WebActivator.ApplicationShutdownMethod(typeof(BombaySapphireCds.App_Start.PodMonitorConfig), "Shutdown")]
namespace BombaySapphireCds.App_Start
{
public static class PodMonitorConfig
{
private static PodMonitorJob m_job;
public static void Start()
{
m_job = new PodMonitorJob(TimeSpan.FromSeconds(20));
}
public static void Shutdown()
{
m_job.Dispose();
}
}
}
and the class to do the actual work... (put this anywhere you like)
using System;
using System.Threading;
using System.Threading.Tasks;
namespace BombaySapphireCds.Jobs
{
public class PodMonitorJob : IDisposable
{
private CancellationTokenSource m_cancel;
private Task m_task;
private TimeSpan m_interval;
private bool m_running;
public PodMonitorJob(TimeSpan interval)
{
m_interval = interval;
m_running = true;
m_cancel = new CancellationTokenSource();
m_task = Task.Run(() => TaskLoop(), m_cancel.Token);
}
private void TaskLoop()
{
while (m_running)
{
//
// Do monitoring work here.
//
Thread.Sleep(m_interval);
}
}
public void Dispose()
{
m_running = false;
if (m_cancel != null)
{
try
{
m_cancel.Cancel();
m_cancel.Dispose();
}
catch
{
}
finally
{
m_cancel = null;
}
}
}
}
}
This has become the new standard for background task execution on the web. It's a NuGet package and it's called HangFire - https://github.com/HangfireIO/Hangfire. The tasks persist even beyond apppool recycling.

Pattern for calling WCF service using async/await

I generated a proxy with task-based operations.
How should this service be invoked properly (disposing of the ServiceClient and the OperationContext afterwards) using async/await?
My first attempt was:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return await helper.Proxy.GetHomeInfoAsync(timestamp);
}
}
Being ServiceHelper a class which creates the ServiceClient and the OperationContextScope and disposes of them afterwards:
try
{
if (_operationContextScope != null)
{
_operationContextScope.Dispose();
}
if (_serviceClient != null)
{
if (_serviceClient.State != CommunicationState.Faulted)
{
_serviceClient.Close();
}
else
{
_serviceClient.Abort();
}
}
}
catch (CommunicationException)
{
_serviceClient.Abort();
}
catch (TimeoutException)
{
_serviceClient.Abort();
}
catch (Exception)
{
_serviceClient.Abort();
throw;
}
finally
{
_operationContextScope = null;
_serviceClient = null;
}
However, this failed miserably when calling two services at the same time with the following error: "This OperationContextScope is being disposed on a different thread than it was created."
MSDN says:
Do not use the asynchronous “await” pattern within a OperationContextScope block. When the continuation occurs, it may run on a different thread and OperationContextScope is thread specific. If you need to call “await” for an async call, use it outside of the OperationContextScope block.
So that's the problem! But, how do we fix it properly?
This guy did just what MSDN says:
private async void DoStuffWithDoc(string docId)
{
var doc = await GetDocumentAsync(docId);
if (doc.YadaYada)
{
// more code here
}
}
public Task<Document> GetDocumentAsync(string docId)
{
var docClient = CreateDocumentServiceClient();
using (new OperationContextScope(docClient.InnerChannel))
{
return docClient.GetDocumentAsync(docId);
}
}
My problem with his code, is that he never calls Close (or Abort) on the ServiceClient.
I also found a way of propagating the OperationContextScope using a custom SynchronizationContext. But, besides the fact that it's a lot of "risky" code, he states that:
It’s worth noting that it does have a few small issues regarding the disposal of operation-context scopes (since they only allow you to dispose them on the calling thread), but this doesn’t seem to be an issue since (at least according to the disassembly), they implement Dispose() but not Finalize().
So, are we out of luck here? Is there a proven pattern for calling WCF services using async/await AND disposing of BOTH the ServiceClient and the OperationContextScope? Maybe someone form Microsoft (perhaps guru Stephen Toub :)) can help.
Thanks!
[UPDATE]
With a lot of help from user Noseratio, I came up with something that works: do not use OperationContextScope. If you are using it for any of these reasons, try to find a workaround that fits your scenario. Otherwise, if you really, really, need OperationContextScope, you'll have to come up with an implementation of a SynchronizationContext that captures it, and that seems very hard (if at all possible - there must be a reason why this isn't the default behavior).
So, the full working code is:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return await helper.Proxy.GetHomeInfoAsync(timestamp);
}
}
With ServiceHelper being:
public class ServiceHelper<TServiceClient, TService> : IDisposable
where TServiceClient : ClientBase<TService>, new()
where TService : class
{
protected bool _isInitialized;
protected TServiceClient _serviceClient;
public TServiceClient Proxy
{
get
{
if (!_isInitialized)
{
Initialize();
_isInitialized = true;
}
else if (_serviceClient == null)
{
throw new ObjectDisposedException("ServiceHelper");
}
return _serviceClient;
}
}
protected virtual void Initialize()
{
_serviceClient = new TServiceClient();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
try
{
if (_serviceClient != null)
{
if (_serviceClient.State != CommunicationState.Faulted)
{
_serviceClient.Close();
}
else
{
_serviceClient.Abort();
}
}
}
catch (CommunicationException)
{
_serviceClient.Abort();
}
catch (TimeoutException)
{
_serviceClient.Abort();
}
catch (Exception)
{
_serviceClient.Abort();
throw;
}
finally
{
_serviceClient = null;
}
}
}
}
Note that the class supports extension; perhaps you need to inherit and provide credentials.
The only possible "gotcha" is that in GetHomeInfoAsync, you can't just return the Task you get from the proxy (which should seem natural, why create a new Task when you already have one). Well, in this case you need to await the proxy Task and then close (or abort) the ServiceClient, otherwise you'll be closing it right away after invoking the service (while bytes are being sent over the wire)!
OK, we have a way to make it work, but it'd be nice to get an answer from an authoritative source, as Noseratio states.
I think a feasible solution might be to use a custom awaiter to flow the new operation context via OperationContext.Current. The implementation of OperationContext itself doesn't appear to require thread affinity. Here is the pattern:
async Task TestAsync()
{
using(var client = new WcfAPM.ServiceClient())
using (var scope = new FlowingOperationContextScope(client.InnerChannel))
{
await client.SomeMethodAsync(1).ContinueOnScope(scope);
await client.AnotherMethodAsync(2).ContinueOnScope(scope);
}
}
Here is the implementation of FlowingOperationContextScope and ContinueOnScope (only slightly tested):
public sealed class FlowingOperationContextScope : IDisposable
{
bool _inflight = false;
bool _disposed;
OperationContext _thisContext = null;
OperationContext _originalContext = null;
public FlowingOperationContextScope(IContextChannel channel):
this(new OperationContext(channel))
{
}
public FlowingOperationContextScope(OperationContext context)
{
_originalContext = OperationContext.Current;
OperationContext.Current = _thisContext = context;
}
public void Dispose()
{
if (!_disposed)
{
if (_inflight || OperationContext.Current != _thisContext)
throw new InvalidOperationException();
_disposed = true;
OperationContext.Current = _originalContext;
_thisContext = null;
_originalContext = null;
}
}
internal void BeforeAwait()
{
if (_inflight)
return;
_inflight = true;
// leave _thisContext as the current context
}
internal void AfterAwait()
{
if (!_inflight)
throw new InvalidOperationException();
_inflight = false;
// ignore the current context, restore _thisContext
OperationContext.Current = _thisContext;
}
}
// ContinueOnScope extension
public static class TaskExt
{
public static SimpleAwaiter<TResult> ContinueOnScope<TResult>(this Task<TResult> #this, FlowingOperationContextScope scope)
{
return new SimpleAwaiter<TResult>(#this, scope.BeforeAwait, scope.AfterAwait);
}
// awaiter
public class SimpleAwaiter<TResult> :
System.Runtime.CompilerServices.INotifyCompletion
{
readonly Task<TResult> _task;
readonly Action _beforeAwait;
readonly Action _afterAwait;
public SimpleAwaiter(Task<TResult> task, Action beforeAwait, Action afterAwait)
{
_task = task;
_beforeAwait = beforeAwait;
_afterAwait = afterAwait;
}
public SimpleAwaiter<TResult> GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
// don't do anything if the task completed synchronously
// (we're on the same thread)
if (_task.IsCompleted)
return true;
_beforeAwait();
return false;
}
}
public TResult GetResult()
{
return _task.Result;
}
// INotifyCompletion
public void OnCompleted(Action continuation)
{
_task.ContinueWith(task =>
{
_afterAwait();
continuation();
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
SynchronizationContext.Current != null ?
TaskScheduler.FromCurrentSynchronizationContext() :
TaskScheduler.Current);
}
}
}
Simple way is to move the await outside the using block
public Task<Document> GetDocumentAsync(string docId)
{
var docClient = CreateDocumentServiceClient();
using (new OperationContextScope(docClient.InnerChannel))
{
var task = docClient.GetDocumentAsync(docId);
}
return await task;
}
I decide to write my own code that helps with this, posting in case this helps anyone. Seems to be a little less to go wrong (unforeseen races etc) vs the SimpleAwaiter implementation above but you be the judge:
public static class WithOperationContextTaskExtensions
{
public static ContinueOnOperationContextAwaiter<TResult> WithOperationContext<TResult>(this Task<TResult> #this, bool configureAwait = true)
{
return new ContinueOnOperationContextAwaiter<TResult>(#this, configureAwait);
}
public static ContinueOnOperationContextAwaiter WithOperationContext(this Task #this, bool configureAwait = true)
{
return new ContinueOnOperationContextAwaiter(#this, configureAwait);
}
public class ContinueOnOperationContextAwaiter : INotifyCompletion
{
private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _awaiter;
private OperationContext _operationContext;
public ContinueOnOperationContextAwaiter(Task task, bool continueOnCapturedContext = true)
{
if (task == null) throw new ArgumentNullException("task");
_awaiter = task.ConfigureAwait(continueOnCapturedContext).GetAwaiter();
}
public ContinueOnOperationContextAwaiter GetAwaiter() { return this; }
public bool IsCompleted { get { return _awaiter.IsCompleted; } }
public void OnCompleted(Action continuation)
{
_operationContext = OperationContext.Current;
_awaiter.OnCompleted(continuation);
}
public void GetResult()
{
OperationContext.Current = _operationContext;
_awaiter.GetResult();
}
}
public class ContinueOnOperationContextAwaiter<TResult> : INotifyCompletion
{
private readonly ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter _awaiter;
private OperationContext _operationContext;
public ContinueOnOperationContextAwaiter(Task<TResult> task, bool continueOnCapturedContext = true)
{
if (task == null) throw new ArgumentNullException("task");
_awaiter = task.ConfigureAwait(continueOnCapturedContext).GetAwaiter();
}
public ContinueOnOperationContextAwaiter<TResult> GetAwaiter() { return this; }
public bool IsCompleted { get { return _awaiter.IsCompleted; } }
public void OnCompleted(Action continuation)
{
_operationContext = OperationContext.Current;
_awaiter.OnCompleted(continuation);
}
public TResult GetResult()
{
OperationContext.Current = _operationContext;
return _awaiter.GetResult();
}
}
}
Usage (a little manual and nesting is untested...):
/// <summary>
/// Make a call to the service
/// </summary>
/// <param name="action"></param>
/// <param name="endpoint"> </param>
public async Task<ResultCallWrapper<TResult>> CallAsync<TResult>(Func<T, Task<TResult>> action, EndpointAddress endpoint)
{
using (ChannelLifetime<T> channelLifetime = new ChannelLifetime<T>(ConstructChannel(endpoint)))
{
// OperationContextScope doesn't work with async/await
var oldContext = OperationContext.Current;
OperationContext.Current = new OperationContext((IContextChannel)channelLifetime.Channel);
var result = await action(channelLifetime.Channel)
.WithOperationContext(configureAwait: false);
HttpResponseMessageProperty incomingMessageProperty = (HttpResponseMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
string[] keys = incomingMessageProperty.Headers.AllKeys;
var headersOrig = keys.ToDictionary(t => t, t => incomingMessageProperty.Headers[t]);
OperationContext.Current = oldContext;
return new ResultCallWrapper<TResult>(result, new ReadOnlyDictionary<string, string>(headersOrig));
}
}
Async flow is supported from .Net 4.6.2.
We have an ASP.Net WebApi application running on .Net 4.6 where we used the accepted answer. TaskScheduler.FromCurrentSynchronizationContext() caused deadlock issues when the current synchronization context is AspNetSynchronizationContext.
I believe the continuation task was queued after the actual task, causing the actual task is waiting on the continuation whereas the continuation task must run to complete the actual task. i.e. tasks are both waiting on each other.
So I fixed the issue by changing using continuation task to use TaskAwaiter. See: https://blogs.msdn.microsoft.com/lucian/2012/12/11/how-to-write-a-custom-awaiter/
It's been a while on this one, but I'll chime in with my own home-baked solution.
If one doesn't mind doing without OperationContextScope, one might consider something along these lines:
Extension methods
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace Intexx.ServiceModel
{
public static class WcfExtensions
{
[DebuggerStepThrough]
public static void Call<TChannel>(this TChannel Client, Action<TChannel> Method) where TChannel : ICommunicationObject
{
try
{
Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
[DebuggerStepThrough]
public static TResult Call<TChannel, TResult>(this TChannel Client, Func<TChannel, TResult> Method) where TChannel : ICommunicationObject
{
try
{
return Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
[DebuggerStepThrough]
public async static Task CallAsync<TChannel>(this TChannel Client, Func<TChannel, Task> Method) where TChannel : ICommunicationObject
{
try
{
await Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
[DebuggerStepThrough]
public async static Task<TResult> CallAsync<TChannel, TResult>(this TChannel Client, Func<TChannel, Task<TResult>> Method) where TChannel : ICommunicationObject
{
try
{
return await Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
private static void Cleanup<TChannel>(TChannel Client) where TChannel : ICommunicationObject
{
try
{
if (Client.IsNotNull)
{
if (Client.State == CommunicationState.Faulted)
Client.Abort();
else
Client.Close();
}
}
catch (Exception ex)
{
Client.Abort();
if (!ex is CommunicationException && !ex is TimeoutException)
throw new Exception(ex.Message, ex);
}
finally
{
Client = null;
}
}
}
}
Client class
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace Reader
{
public class Client
{
public static CemReaderClient Create()
{
Tuple<Channels.Binding, EndpointAddress, double> oService;
try
{
oService = Main.Services(typeof(ICemReader));
return new CemReaderClient(oService.Item1, oService.Item2);
}
catch (KeyNotFoundException ex)
{
return null;
}
}
}
}
Usage (in VB, as the code wouldn't convert)
Using oReader As Reader.CemReaderClient = Reader.Client.Create
If oReader.IsNotNothing Then
Dim lIsReading = Await oReader.CallAsync(Function(Reader As Reader.CemReaderClient)
Me.ConfigFilePath = If(Me.ConfigFilePath, Reader.GetConfigFilePath)
Me.BackupDrive = If(Me.BackupDrive, Reader.GetBackupDrive)
Me.SerialPort = If(Me.SerialPort, Reader.GetSerialPort)
Me.LogFolder = If(Me.LogFolder, Reader.GetLogFolder)
Return Reader.GetIsReadingAsync
End Function)
End If
End Using
I've had this running reliably in production under frequency loads of around 15 calls/sec on the client side (that's as fast as serial processing would allow). That was on a single thread, though—this hasn't been rigorously tested for thread safety. YMMV.
In my case, I decided to roll the extension methods into their own private NuGet package. The whole construct has turned out to be pretty handy.
This will have to be reevaluated, of course, if OperationContextScope ever ends up being needed.
The bit with the Tuple in the Client class is for Service Discovery support. If anyone would like to see that code as well, give a shout and I'll update my answer.
I am a little bit confused, I found this Blog : Task-based asynchronous operation in WCF
There this is a async wcf communication:
[ServiceContract]
public interface IMessage
{
[OperationContract]
Task<string> GetMessages(string msg);
}
public class MessageService : IMessage
{
async Task<string> IMessage.GetMessages(string msg)
{
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(10000);
return "Return from Server : " + msg;
});
return await task.ConfigureAwait(false);
}
}
Client:
var client = new Proxy("BasicHttpBinding_IMessage");
var task = Task.Factory.StartNew(() => client.GetMessages("Hello"));
var str = await task;
So is this also a good way??
I ran into the same issue, however it dawned on me that I didn't need to use async/await at all.
Since you are not post processing the result, there is no need to wait for the reply. If you do need to process the result, just use the old fashion TPL continuation.
public Task<MyDomainModel> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return helper.Proxy.GetHomeInfoAsync(timestamp).ContinueWith(antecedent=>processReplay(antecedent.Result));
}
}
I don't know if this helps, but after seeing this question on my search to answer the same question, I came upon this.
Leading from that, I should think your code should look something like this:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var client = CreateDocumentServiceClient())
{
await client.BeginGetHomeInfoAsync(timestamp);
}
}
I realise my answer comes rather late :P but it might help someone else.

Calling async method does not set member variable

This code it´s write in C# in visual studio 2012 I ´ve using winrt tool kit
Hi I tried create this loadGrupos to catch the file grupo.txt and read and load his content in to the class Grupos but I don´t know what´s happen the list grupos recive the content from the json but when I callend the loadGrupos the variable grupos don´t expose nothing.
I really don´t know what´s going on. I tried debug and I didn´t found any error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Windows.Storage;
using Windows.ApplicationModel;
using WinRTXamlToolkit.IO.Extensions;
using Windows.UI.Popups;
namespace xxx;
public class MyJConverter
{
public String _Path;
//private Windows.ApplicationModel.Package package;
// private Windows.Storage.StorageFolder installedLocation;
private StorageFolder _Folder = Windows.Storage.ApplicationData.Current.LocalFolder;
//KnownFolders.DocumentsLibrary
public MyJConverter() {
// package = Windows.ApplicationModel.Package.Current;
// installedLocation = package.InstalledLocation;
}
public void save(Object obj)
{
_Path = JsonConvert.SerializeObject(obj);
gravandoUmDocumento("data",_Path);
}
public void saveGrupo(Object obj)
{
_Path = JsonConvert.SerializeObject(obj);
gravandoUmDocumento("grupo", _Path);
}
public async void gravandoUmDocumento(String nomeDoArquivo,String menssagem) {
// var _Folder = Windows.Storage.ApplicationData.Current.LocalFolder;
// var _Folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
//await menssagem.WriteToFile(nomeDoArquivo + "1.txt", KnownFolders.DocumentsLibrary);
await menssagem.WriteToFile(nomeDoArquivo + ".txt", _Folder);
}
private List<Ano> anos;
public List<Ano> load()
{
leituraDeUmArquivo("data").Wait();
if (anos != null)
{
return anos;
}
return null;
}
private List<Grupos> grupos;
public List<Grupos> Grupos
{
get { return grupos; }
set { grupos = value; }
}
public List<Grupos> loadGrupos()
{
leituraDeUmArquivo("grupo").Wait();
{
if (grupos != null)
{
return grupos;
}
else
return null;
}
}
public async Task leituraDeUmArquivo(String arquivoASerLido)
{
String leitura = "";
//leitura do data
try
{
// settings
var _Path =arquivoASerLido + ".txt";
// acquire file
var _File = await _Folder.GetFileAsync(_Path);
// read content
leitura = (String) await Windows.Storage.FileIO.ReadTextAsync(_File);
// leitura = (String)_ReadThis;
}
catch {
// leituraDeUmArquivo(arquivoASerLido);
}
if (leitura != "")
{
if (arquivoASerLido.Equals("data"))
{
try
{
anos = JsonConvert.DeserializeObject<List<Ano>>(leitura);
}
catch {
}
}
if (arquivoASerLido.Equals("grupo"))
{
try{
grupos = JsonConvert.DeserializeObject<List<Grupos>>(leitura);
}
catch { }
}
}
}
}
HI I did the modifications you recomend but the problem didn´t solved so I post all my code.
I really didn´t found why the winrt can´t load the file, some time win 8 load some times no.
Now with the modificiations the app block and do go to front.
if I go with debug the visual found the file, if I go only run no.
There should be warning about "calling async method without awaiting" (or something like this).
You need to await for completion of async method instead of just calling it.
I.e. cheap and dirty (not good idea for WinRT) approach is to call Task.Wait on result of leituraDeUmArquivo (the method need to be updated to return Task):
leituraDeUmArquivo("grupo").Wait();
Better approach is to make code properly asynchronous and just await call to leituraDeUmArquivo (your loadGrupos function will likely need to be marked async too and handled appropriately).
Note: to make await/ .Wait() working leituraDeUmArquivo should return Task.
public async Task leituraDeUmArquivo(String arquivoASerLido)
// don't need to touch body of the method.

Asynchronous insert in Azure Table

How to asynchronously save an entity to Windows Azure Table Service?
The code below works synchronously but raises an exception when trying to save asynchronously.
This statement:
context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
(asyncResult => context.EndSaveChanges(asyncResult)), null);
Results in System.ArgumentException: "The current object did not originate the async result. Parameter name: asyncResult".
Additionally, what's the correct pattern for creating the service context when saving asynchronously? Should I create a separate context for each write operation? Is it too expensive (e.g. requiring a call over the network)?
TableStorageWriter.cs:
using System;
using System.Data.Services.Client;
using System.Diagnostics;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
namespace WorkerRole1
{
public class TableStorageWriter
{
private const string _tableName = "StorageTest";
private readonly CloudStorageAccount _storageAccount;
private CloudTableClient _tableClient;
public TableStorageWriter()
{
_storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
_tableClient = _storageAccount.CreateCloudTableClient();
_tableClient.CreateTableIfNotExist(_tableName);
}
public void Write(string message)
{
try
{
DateTime now = DateTime.UtcNow;
var entity = new StorageTestEntity
{
Message = message,
PartitionKey = string.Format("{0:yyyy-MM-dd}", now),
RowKey = string.Format("{0:HH:mm:ss.fff}-{1}", now, Guid.NewGuid())
};
// Should I get this context before each write? It is efficient?
TableServiceContext context = _tableClient.GetDataServiceContext();
context.AddObject(_tableName, entity);
// This statement works but it's synchronous
context.SaveChangesWithRetries();
// This attempt at saving asynchronously results in System.ArgumentException:
// The current object did not originate the async result. Parameter name: asyncResult
// context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
// (asyncResult => context.EndSaveChanges(asyncResult)), null);
}
catch (StorageClientException e)
{
Debug.WriteLine("Error: {0}", e.Message);
Debug.WriteLine("Extended error info: {0} : {1}",
e.ExtendedErrorInformation.ErrorCode,
e.ExtendedErrorInformation.ErrorMessage);
}
}
}
internal class StorageTestEntity : TableServiceEntity
{
public string Message { get; set; }
}
}
Called from WorkerRole.cs:
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure.ServiceRuntime;
using log4net;
namespace WorkerRole1
{
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
var storageWriter = new TableStorageWriter();
while (true)
{
Thread.Sleep(10000);
storageWriter.Write("Working...");
}
}
public override bool OnStart()
{
ServicePointManager.DefaultConnectionLimit = 12;
return base.OnStart();
}
}
}
Examples using Windows Azure SDK for .NET 1.8.
You should call EndSaveChangesWithRetries instead of EndSaveChanges, as otherwise the IAsyncResult object returned by BeginSaveChangesWithRetries cannot be used by EndSaveChanges. So, could you please try changing your End method call as below?
context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
(asyncResult => context.EndSaveChangesWithRetries(asyncResult)),
null);
And for your other question, I would recommend creating a new TableServiceContext for each call, as DataServiceContext is not stateless (MSDN) and the way you implemented TableStorageWriter.Write with the asynchronous call might allow concurrent operations. Actually, in Storage Client Library 2.0, we explicitly prevented concurrent operations that uses a single TableServiceContext object. Moreover, creating a TableServiceContext does not result in a request to Azure Storage.

Categories