'unitOfWork parameter cannot be null' in Background Worker - c#

I've started getting these errors. It was working perfectly on my previous server.
using System;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Threading.BackgroundWorkers;
using EMS.IPs;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
using System.Linq;
using EMS.Contacts;
using System.Collections.Concurrent;
using Abp.Domain.Uow;
using System.Collections.Generic;
using EMS.EmailValidation;
using Microsoft.AspNetCore.SignalR;
using KellermanSoftware.NetEmailValidation;
using System.Net;
using System.Collections;
using System.Threading;
using System.ComponentModel;
using System.Transactions;
namespace EMS.BackgroundWorkers
{
public class ContactValidationBackgroundWorker : BackgroundWorkerBase, ITransientDependency
{
private readonly IRepository<IP> _ipsRepository;
private readonly IRepository<Contact> _contactsRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IUnitOfWorkManager _unitOfWorkManager2;
private readonly IRepository<Contact> _contactRepository;
private BackgroundWorker bgworker = new BackgroundWorker();
ActionBlock<ValidationObject> workerBlock;
public ContactValidationBackgroundWorker(
IRepository<IP> ipsRepository,
IRepository<Contact> contactsRepository,
IUnitOfWorkManager unitOfWorkManager,
IUnitOfWorkManager unitOfWorkManager2,
IRepository<Contact> contactRepository)
{
_ipsRepository = ipsRepository;
_contactsRepository = contactsRepository;
_unitOfWorkManager = unitOfWorkManager;
_unitOfWorkManager2 = unitOfWorkManager2;
_contactRepository = contactRepository;
bgworker.DoWork += Worker;
}
public override void Start()
{
base.Start();
bgworker.RunWorkerAsync();
}
public override void Stop()
{
bgworker.DoWork -= Worker;
}
public void Worker(object sender, DoWorkEventArgs e)
{
using (var unitOfWork = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
{
var contacts = _contactsRepository.GetAll().Where(x => !x.IsChecked);
if (!contacts.Any())
{
Logger.Debug("No contacts");
return;
}
workerBlock = new ActionBlock<ValidationObject>(
async (arg) => await Validate(arg),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5
});
foreach (var contact in contacts)
{
workerBlock.Post(new ValidationObject()
{
Contact = contact
});
}
unitOfWork.Complete();
}
Logger.Debug("End posting jobs to threads. Awaits results...");
workerBlock.Complete();
workerBlock.Completion.Wait();
}
public override void WaitToStop()
{
base.WaitToStop();
}
private async Task Validate(ValidationObject validationObject)
{
try
{
using (var contactUnitOfWork = _unitOfWorkManager2.Begin(TransactionScopeOption.RequiresNew))
{
Contact contact = validationObject.Contact;
contact.IsChecked = true;
await _contactRepository.UpdateAsync(contact);
await contactUnitOfWork.CompleteAsync();
}
} catch (Exception ex) {
Logger.Error(ex.ToString());
throw;
}
}
}
public class ValidationResult
{
public ValidationResult()
{
IsValid = false;
Message = "";
}
public string Message { get; set; }
public bool IsValid { get; set; }
}
public class ValidationObject
{
public Contact Contact { get; set; }
}
}
It works inside background worker; it worked before. Now it doesn't. Contact object is not null.
It seems to ask me to add unitOfWork parameter to Update method. Please help me figure this out.
ERROR 2017-12-26 12:02:34,768 [14 ] orkers.ContactValidationBackgroundWorker - System.ArgumentNullException: Value cannot be null.
Parameter name: unitOfWork
at Abp.EntityFrameworkCore.Uow.UnitOfWorkExtensions.GetDbContext[TDbContext](IActiveUnitOfWork unitOfWork, Nullable`1 multiTenancySide)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.Update(TEntity entity)
at Castle.Proxies.Invocations.IRepository`2_Update_8.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IRepository`1Proxy_3.Update(Contact entity)
at EMS.BackgroundWorkers.ContactValidationBackgroundWorker.<Validate>d__21.MoveNext() in /Users/grinay/Projects/EMSBackend/src/EMS.Application/BackgroundWorkers/ContactValidationBackgroundWorker.cs:line 329
UPDATE1
ERROR 2017-12-27 05:31:34,500 [9 ] orkers.ContactValidationBackgroundWorker - System.ArgumentNullException: Value cannot be null.
Parameter name: unitOfWork
at Abp.EntityFrameworkCore.Uow.UnitOfWorkExtensions.GetDbContext[TDbContext](IActiveUnitOfWork unitOfWork, Nullable`1 multiTenancySide)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.UpdateAsync(TEntity entity)
at Castle.Proxies.Invocations.IRepository`2_UpdateAsync_8.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformAsyncUow(IInvocation invocation, UnitOfWorkOptions options)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IRepository`1Proxy_3.UpdateAsync(Contact entity)
at EMS.BackgroundWorkers.ContactValidationBackgroundWorker.<>c__DisplayClass23_0.<<Validate>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at Nito.AsyncEx.AsyncContext.Run(Func`1 action)
at EMS.BackgroundWorkers.ContactValidationBackgroundWorker.Validate(ValidationObject validationObject)

You cannot use async methods with unitOfWork like that in background worker.
Make the changes in these 5 lines:
public void Worker(object sender, DoWorkEventArgs e)
{
// ...
workerBlock = new ActionBlock<ValidationObject>(
(arg) => Validate(arg), // This line #1
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5
});
// ...
}
private void Validate(ValidationObject validationObject) // This line #2
{
try
{
using (var contactUnitOfWork = _unitOfWorkManager2.Begin(TransactionScopeOption.RequiresNew))
{
Contact contact = validationObject.Contact;
contact.IsChecked = true;
AsyncHelper.RunSync(async () => // This line #3
{ // This line #4
await _contactRepository.UpdateAsync(contact);
await contactUnitOfWork.CompleteAsync();
}); // This line #5
}
} catch (Exception ex) {
Logger.Error(ex.ToString());
throw;
}
}

Related

Autofac: Autofac.Core.DependencyResolutionException

The server runs but when I try to connect to the server I recieve this Exception:
2023-01-12 15:10:00,023 [12] ERROR Photon.SocketServer.Peers.ManagedPeer - Autofac.Core.DependencyResolutionException:
An exception was thrown while activating NinjaBricks.NinjaPhoton.Implementation.Client.PhotonClientPeer ->
NinjaBricks.Framework.Implementation.Messaging.ClientHandlerList ->
λ:NinjaBricks.Framework.Interfaces.Messaging.IHandler`1[[NinjaBricks.Framework.Interfaces.Client.IClientPeer, NinjaBricks.Framework,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]][] -> NinjaBricks.NinjaPhoton.Implementation.Handler.ClientRequestForwardHandler.
---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'NinjaBricks.NinjaPhoton.Implementation.Handler.ClientRequestForwardHandler' can be invoked with the available services and parameters:
Cannot resolve parameter 'NinjaBricks.Framework.Interfaces.Support.IClientCodeRemover clientCodeRemover' of constructor
'Void .ctor(ExitGames.Logging.ILogger,
NinjaBricks.Framework.Interfaces.Server.IServerConnectionCollection`2
[NinjaBricks.Framework.Interfaces.Config.IServerType,
NinjaBricks.Framework.Interfaces.Server.IServerPeer],
NinjaBricks.Framework.Interfaces.Support.IClientCodeRemover,
NinjaBricks.Framework.Interfaces.Config.IServerType)'.
en Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(ConstructorInfo[] availableConstructors, IComponentContext context, IEnumerable`1 parameters)
en Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
en Autofac.Core.Resolving.InstanceLookup.CreateInstance(IEnumerable`1 parameters)
--- Fin del seguimiento de la pila de la excepción interna ---
en Autofac.Core.Resolving.InstanceLookup.CreateInstance(IEnumerable`1 parameters)
en Autofac.Core.Resolving.InstanceLookup.Execute()
en Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
en Autofac.Core.Resolving.ResolveOperation.Execute(ResolveRequest request)
en lambda_method(Closure , InitRequest )
en NinjaBricks.NinjaPhoton.Implementation.PhotonPeerFactory.CreatePeer[T](IPeerConfig config) en D:\Users\pndia\Documents\GitHub\NinjaBricks\ninja-bricks-game-server\NinjaBricks.NinjaPhoton\Implementation\PhotonPeerFactory.cs:línea 61
en Photon.SocketServer.Peers.ManagedPeer.CreatePeerBase(InitRequest initRequest)
The code was made by other programmer and It is old code, but I Can't run it properly and i have no documentation about the code.
This is the ClientRequestForwardHandler class:
using ExitGames.Logging;
using NinjaBricks.Common;
using NinjaBricks.Common.Codes;
using NinjaBricks.Framework.Implementation.Config;
using NinjaBricks.Framework.Implementation.Messaging;
using NinjaBricks.Framework.Interfaces.Client;
using NinjaBricks.Framework.Interfaces.Config;
using NinjaBricks.Framework.Interfaces.Messaging;
using NinjaBricks.Framework.Interfaces.Server;
using NinjaBricks.Framework.Interfaces.Support;
using System;
using System.Linq;
namespace NinjaBricks.NinjaPhoton.Implementation.Handler
{
public class ClientRequestForwardHandler : IHandler<IClientPeer>, IDefaultRequestHandler<IClientPeer>
{
private readonly IServerConnectionCollection<IServerType, IServerPeer> _serverConnectionCollection;
private readonly IClientCodeRemover _clientCodeRemover;
private readonly IServerType _serverType;
public ILogger Log { get; set; }
public byte Code { get => 0x0ff; }
public int? SubCode { get => null; }
public MessageType Type { get => MessageType.Request; }
public ClientRequestForwardHandler(ILogger log,
IServerConnectionCollection<IServerType, IServerPeer> serverConnectionCollection,
IClientCodeRemover clientCodeRemover,
IServerType serverType)
{
Log = log;
_serverConnectionCollection = serverConnectionCollection;
_clientCodeRemover = clientCodeRemover;
_serverType = serverType;
}
public bool HandleMessage(IMessage message, IClientPeer clientPeer)
{
if (!message.Parameters.ContainsKey((byte)ParameterCode.ServerType))
{
return false;
}
var serverType = _serverType.GetServerType(Convert.ToInt32(message.Parameters[(byte)ParameterCode.ServerType]));
var server = _serverConnectionCollection.GetServersByType<IServerPeer>(serverType).FirstOrDefault();
if (server != null)
{
_clientCodeRemover.RemoveServerType(message);
_clientCodeRemover.RemovePeerId(message);
AddMessageCodes(message, clientPeer);
server.SendMessage(message);
return true;
}
return false;
}
private void AddMessageCodes(IMessage message, IClientPeer clientPeer)
{
message.Parameters.Add((byte)ParameterCode.PeerId, clientPeer.PeerId.ToByteArray());
}
}
}
And this is the IClientCodeRemover:
using NinjaBricks.Common.Codes;
using NinjaBricks.Framework.Interfaces.Messaging;
using NinjaBricks.Framework.Interfaces.Support;
namespace NinjaBricks.Framework.Implementation.Support
{
public class ClientCodeRemover : IClientCodeRemover
{
public void RemovePeerId(IMessage message)
{
message.Parameters.Remove((byte)MessageParameterCode.PeerId);
}
public void RemoveServerType(IMessage message)
{
message.Parameters.Remove((byte)ParameterCode.ServerType);
}
public void RemoveName(IMessage message)
{
message.Parameters.Remove((byte)ParameterCode.Name);
}
}
}
Also here the configs of autofac:
using Autofac;
using NinjaBricks.NinjaPhoton.Implementation;
using NinjaBricks.NinjaPhoton.Implementation.Client;
using NinjaBricks.NinjaPhoton.Implementation.Data;
using NinjaBricks.NinjaPhoton.Implementation.Handler;
using NinjaBricks.NinjaPhoton.Implementation.Server;
using NinjaBricks.Framework.Implementation.Client;
using NinjaBricks.Framework.Implementation.Config;
using NinjaBricks.Framework.Implementation.Messaging;
using NinjaBricks.Framework.Implementation.Server;
namespace NinjaBricks.NinjaPhoton.Modules
{
public class ProxyServerModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<ServerApplication>().AsImplementedInterfaces().SingleInstance();
builder.RegisterType<PhotonPeerFactory>().AsImplementedInterfaces().SingleInstance();
builder.RegisterType<PeerConfig>().AsImplementedInterfaces();
builder.RegisterType<SubServerClientPeer>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<PhotonClientPeer>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<PhotonServerPeer>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<ServerConnectionCollection>().AsImplementedInterfaces().SingleInstance();
builder.RegisterType<ClientConnectionCollection>().AsImplementedInterfaces().SingleInstance();
builder.RegisterType<ServerHandlerList>().AsImplementedInterfaces();
builder.RegisterType<EventForwardHandler>().AsImplementedInterfaces();
builder.RegisterType<RequestForwardHandler>().AsImplementedInterfaces();
builder.RegisterType<ResponseForwardHandler>().AsImplementedInterfaces();
builder.RegisterType<ClientHandlerList>().AsImplementedInterfaces();
builder.RegisterType<ClientRequestForwardHandler>().AsImplementedInterfaces();
builder.RegisterType<ServerRegistrationHandler>().AsImplementedInterfaces();
builder.RegisterType<ServerData>().AsImplementedInterfaces();
}
}
}
Autofac version 5.2.0
Based on the provided code it seems that you have forgot to register ClientCodeRemover. Try adding:
builder.RegisterType<ClientCodeRemover>().AsImplementedInterfaces();
To your ProxyServerModule.Load method.

Asynchronous Queue Callback from Web Request

I have a web app that talks to web socket thats connected to a third party service. The socket only has one connection, given that I can have many API calls. I am adding a message to a message queue and then process one at a time. I put together a proof of concept below. I'm struggling with the code that waits for the message to be processed and then calls a delegate with the response.
The basic goal is I have a message it goes through a message queue, the socket receives and responses, and then a socket message is returned back to the original request.
Anyone have any ideas for the best approach to wait for a out of context response?
This is the error I am getting, which I can understand because the message is pushed on the queue and the controller exits.
Unhandled exception. System.ObjectDisposedException:
IFeatureCollection has been disposed. Object name: 'Collection'. at
Microsoft.AspNetCore.Http.Features.FeatureReferences1.ThrowContextDisposed() at Microsoft.AspNetCore.Http.Features.FeatureReferences1.ContextDisposed()
at
Microsoft.AspNetCore.Http.Features.FeatureReferences1.Fetch[TFeature](TFeature& cached, Func2 factory) at
Microsoft.AspNetCore.Http.DefaultHttpResponse.get_HasStarted() at
Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse
response, String text, Encoding encoding, CancellationToken
cancellationToken) at
Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse
response, String text, CancellationToken cancellationToken) at
WebApplication1.Startup.<>c__DisplayClass1_0.<b__2>d.MoveNext()
in
C:\Users\martyspc\source\repos\WebApplication1\WebApplication1\Startup.cs:line
97
--- End of stack trace from previous location --- at System.Threading.Tasks.Task.<>c.b__140_1(Object state)
at System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch() at
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace WebApplication1
{
public class MessageProcessor
{
public void Process()
{
while (true)
{
try
{
var message = MessageQueue.GetNextMessage();
message.ProcessedMessageCallBack("Hello From Messages");
}
catch (Exception ex)
{
Console.WriteLine("Message Queue Empty");
}
Thread.Sleep(2000);
}
}
}
public static class MessageQueue
{
private static Queue<Message> Messages { get; set; } = new Queue<Message>();
public static void AddMessage(Message message)
{
Messages.Enqueue(message);
}
public static Message GetNextMessage()
{
return Messages.Dequeue();
}
}
public class Message
{
public string Label { get; set; }
public Action<String> ProcessedMessageCallBack { get; set; }
}
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
var mp = new MessageProcessor();
Thread InstanceCaller = new Thread(new ThreadStart(mp.Process));
// Start the thread.
InstanceCaller.Start();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
Action<string> del = async i => await context.Response.WriteAsync("Hi There");
MessageQueue.AddMessage(new Message() { Label = "Hello World", ProcessedMessageCallBack = del });
});
});
}
}
}
Thank you in advance, Marty.

Signalr Sending messages from server to client c# An unhandled exception has occurred while executing the request

My error:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'AgencyApi.Controllers.LicenseInfoController'. There should only be one applicable constructor.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.TryFindMatchingConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& parameterMap)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& parameterMap)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactory(Type instanceType, Type[] argumentTypes)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.CreateActivator(ControllerActionDescriptor descriptor)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.CreateControllerFactory(ControllerActionDescriptor descriptor)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory.<>c__DisplayClass7_0.<CreateRequestDelegate>b__0(HttpContext context)"
My SignalRhub.cs
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
namespace AgencyApi
{
public class SignalRHub:Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
My LicenseInfoController.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using AgencyApi.Data.Entities;
using Microsoft.AspNetCore.Mvc;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Microsoft.AspNetCore.SignalR;
using AgencyApi;
namespace AgencyApi.Controllers
{
[Route("api/[controller]")]
public class LicenseInfoController : BaseController
{
private readonly ILicenseInfoService _licenseService;
[HttpPost("ConfirmLink")]
public async Task<JObject> ConfirmLink(LicenseInfo value)
{
JObject res = new JObject();
try
{
var menuService = (IMenuService)this.HttpContext.RequestServices.GetService(typeof(IMenuService));
var model = await _licenseService.GetById(value.id);
model.Status = value.Status;
model.Reason = value.Reason;
var result = await _licenseService.Update(model);
res.Add("ok", true);
res.Add("data", JObject.FromObject(result));
}
catch (Exception ex)
{
res.Add("error", ex.Message);
}
SendToAll();
return res;
}
private readonly IHubContext<SignalRHub> _hubContext;
public LicenseInfoController(IHubContext<SignalRHub> hubContext)
{
_hubContext = hubContext;
}
public void SendToAll()
{
_hubContext.Clients.All.SendAsync("Send", "message");
}
}
}
I think you are copying some bad example. I would suggest a different approach
Make you SignalRinterface as a service, not a derivative:
public class SignalRHub
{
public Task SendMessage(string user, string message) =>
_hubContext.Clients.All.SendAsync("ReceiveMessage", user, message);
public Task SendToAll(string message) =>
_hubContext.Clients.All.SendAsync("Send", message);
private readonly IHubContext<Hub> _hubContext;
public SignalRHub(IHubContext<Hub> hubContext) =>
_hubContext = hubContext;
}
Register in Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSignalR();
services.AddSingleton<SignalRHub>();
}
Then add to the controller:
public class LicenseInfoController : Controller
{
[HttpPost]
public async Task<JObject> ConfirmLink(string value)
{
JObject res = new JObject();
await _signalRHub.SendToAll("message");
return res;
}
private readonly SignalRHub _signalRHub;
public LicenseInfoController(SignalRHub signalRHub)
{
_signalRHub = signalRHub;
}
}

InternalClientWebSocket instance cannot be used for communication because it has been transitioned into the 'Aborted' state

I have an exception when I try to receive data from more than three websockets. If I try on only one, two or three websockets it works perfectly.
I get the exception in this line:
tasks.Add(Send(webSocket, "11"));
The exception message:
Exception: System.Net.WebSockets.WebSocketException (0x80004005): The
'System.Net.WebSockets.InternalClientWebSocket' instance cannot be
used for communication because it has been transitioned into the
'Aborted' state. ---> System.OperationCanceledException: The operation
was canceled. at
System.Threading.CancellationToken.ThrowOperationCanceledException()
at
System.Net.WebSockets.WebSocketConnectionStream.d__21.MoveNext()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at
System.Net.WebSockets.WebSocketBase.WebSocketOperation.d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at
System.Net.WebSockets.WebSocketBase.d__45.MoveNext()
at System.Net.WebSockets.WebSocketBase.ThrowIfAborted(Boolean aborted,
Exception innerException) at
System.Net.WebSockets.WebSocketBase.ThrowIfConvertibleException(String
methodName, Exception exception, CancellationToken cancellationToken,
Boolean aborted) at
System.Net.WebSockets.WebSocketBase.d__45.MoveNext()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Here's my code:
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RTLS_GetData_From_WebSockets.App_Code;
namespace RTLS_GetData_From_WebSockets
{
class Program
{
private static object consoleLock = new object();
private const int sendChunkSize = 256;
private const int receiveChunkSize = 256;
private const bool verbose = true;
private static readonly TimeSpan delay = TimeSpan.FromMilliseconds(30000);
private static WebSocket client;
const string host = "ws://localhost:8080";
static void Main(string[] args)
{
Connect(host).Wait();
}
public static async Task Connect(string uri)
{
ClientWebSocket webSocket = null;
try
{
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
List<Task> tasks = new List<Task>();
tasks.Add(Receive(webSocket));
tasks.Add(Send(webSocket, "9"));
tasks.Add(Send(webSocket, "10"));
tasks.Add(Send(webSocket, "11"));
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex);
}
finally
{
if (webSocket != null)
webSocket.Dispose();
Console.WriteLine();
lock (consoleLock)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("WebSocket closed.");
Console.ResetColor();
}
}
}
static UTF8Encoding encoder = new UTF8Encoding();
private static async Task Send(ClientWebSocket webSocket, string ZoneID)
{
byte[] buffer = encoder.GetBytes("{\"method\":\"subscribe\", \"resource\":\"/zones/" + ZoneID + "\"}");
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
while (webSocket.State == WebSocketState.Open)
{
LogStatus(false, buffer, buffer.Length);
await Task.Delay(delay);
}
}
private static async Task Receive(ClientWebSocket webSocket)
{
byte[] buffer = new byte[receiveChunkSize];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
else
{
LogStatus(true, buffer, result.Count);
}
}
}
private static void LogStatus(bool receiving, byte[] buffer, int length)
{
lock (consoleLock)
{
Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Gray;
if (verbose)
{
string tmp = encoder.GetString(buffer);
var data = JsonConvert.DeserializeObject<Zones>(tmp);
Console.WriteLine(data.body.status);
Console.WriteLine();
}
Console.ResetColor();
}
}
}
}
[DataContract]
public class Zones
{
[DataMember(Name = "body")]
public ZoneBody body { get; set; }
}
public class ZoneBody
{
[DataMember(Name = "feed_id")]
public string feed_id { get; set; }
[DataMember(Name = "zone_id")]
public string zone_id { get; set; }
[DataMember(Name = "status")]
public string status { get; set; }
[DataMember(Name = "at")]
public string at { get; set; }
}
This is from MSDN, here is the link.
This operation will not block. The returned Task object will complete
after the send request on the ClientWebSocket instance has completed.
Exactly one send and one receive is supported on each ClientWebSocket
object in parallel.
Call your Connect method one by one.

How do I redirect the message to the corresponding LUIS app

I have a bot with a root LuisDialog and 4 more LuisDialogs each one with a different LUIS model. Following the conversation started here I've implemented a similar DialogFactory strategy.
When a user sends a question that matches "None" intent in my root dialog, I evaluate the rest of dialogs until I find a match and then forward the message to the "winner".
The problem I'm facing is that I'm getting the http error: 429 (Too Many Requests) when querying LUIS (BaseDialog class).
Any ideas about how to face this?
The "None" intent in my root dialog:
[LuisIntent("None")]
public async Task None(IDialogContext context, IAwaitable<IMessageActivity> message, LuisResult result)
{
var activity = await message;
var factory = new DialogFactory();
BaseDialog<object> dialog = await factory.Create(result.Query);
if (dialog != null)
{
await context.Forward(dialog, EndDialog, activity, CancellationToken.None);
}
else
{
await context.PostAsync("No results!");
}
}
public static async Task EndDialog(IDialogContext context, IAwaitable<object> result)
{
//...
}
The DialogFactory class:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Threading.Tasks;
namespace CodeBot.Dialogs
{
public class DialogFactory
{
private static object _lock = new object();
private static List<BaseDialog<object>> Dialogs { get; set; }
public async Task<BaseDialog<object>> Create(string query)
{
query = query.ToLowerInvariant();
EnsureDialogs();
foreach (var dialog in Dialogs)
{
if (await dialog.CanHandle(query))
{
return dialog;
}
}
return null;
}
private void EnsureDialogs()
{
if (Dialogs == null || (Dialogs.Count != 4))
{
lock (_lock)
{
if (Dialogs == null)
{
Dialogs = new List<BaseDialog<object>>();
}
else if (Dialogs.Count != 4)
{
Dialogs.Clear();
}
Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog1));
Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog2));
Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog3));
Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog4));
}
}
}
}
}
And finally, the BaseDialog class (where I'm getting the error):
using Microsoft.Bot.Builder.Dialogs;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Luis;
using System;
namespace CodeBot.Dialogs
{
[Serializable]
public class BaseDialog<R> : LuisDialog<R>
{
public LuisModelAttribute Luis_Model { get; private set; }
public BaseDialog(LuisModelAttribute luisModel) : base(new LuisService(luisModel))
{
Luis_Model = luisModel;
}
public async Task<bool> CanHandle(string query)
{
try
{
var tasks = services.Select(s => s.QueryAsync(query, CancellationToken.None)).ToArray();
var results = await Task.WhenAll(tasks); <-- Error!!!
var winners = from result in results.Select((value, index) => new { value, index })
let resultWinner = BestIntentFrom(result.value)
where resultWinner != null
select new LuisServiceResult(result.value, resultWinner, this.services[result.index]);
var winner = this.BestResultFrom(winners);
return winner != null && !winner.BestIntent.Intent.Equals(Constants.NONE, StringComparison.InvariantCultureIgnoreCase);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine($"CanHandle error: {e.Message}");
return false;
}
}
}
}
The 429 error is caused by your application (key) hitting the LUIS API too heavily.
You need to either throttle your requests to ensure you stay below the threshold of the free tier, or upgrade to the Basic plan which allows 50 requests a second.

Categories

Resources