WCF - Multiple Processes - wcf

I have an wcf SERVICE that get a request of branch code and return 5 products list values.
In server side, each product process takes about 6 sec to be completed, so if I run synchronous it will take 30 seconds. I altered my server code and run them in parallel. It works fine, but it seems that each parallel process get threads from IIS threadspool.
Now I am thinking to run asynchronous each product processes and when all will be finished then return the whole list of products to client. It will be grateful if you help me about that..
How can I run asynchronous these processes in server side ? No matter if client run sync or async. That what I need is to run async product processes in order to serve the results faster.

Try this asynchronous approach with generics type:
namespace InterNameSpace
{
[ServiceContract]
public interface ITestClass
{
[OperationContract]
Task<AnyComplexType> xpto(string baseUrl, string getAsyncUrl);
}
}
namespace Test
{
ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode.PerSession)]
public class TestClass : ITestClass
{
public async Task<AnyComplexType> xpto(string baseUrl, string getAsyncUrl)
{
try
{
return await TestAux.Auxiliar.RetrieveDeserializeObject<AnyComplexType>(baseUrl, getAsyncUrl);
}
catch (Exception)
{
return null;
}
}
}
}
Create a Product complex-type, pass it to your call method. In this method use the keyword async and task to call the deserialized method as asynchronous.
Your deserialized method recieve the baseurl and the controller route. As a genetic type you can pass different complex-type and deserialaze this object and return it.
namespace TestAux
{
public class Auxiliar
{
public static async Task<T> RetrieveDeserializeObject<T>(string baseUrl, string getAsyncUrl) where T : class
{
try
{
T deserializeObject = null;
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(baseUrl);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await httpClient.GetAsync(getAsyncUrl);
//throw an exception if not successful
if (response.EnsureSuccessStatusCode().IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
// DeserializeObject our concrete class into a JSON String
deserializeObject = await Task.Run(() => JsonConvert.DeserializeObject<T>(content));
}
return deserializeObject;
}
catch (Exception)
{
return null;
}
}
}
}

Related

Why can't my xamarin app recieve data from my API call?

Im new to connecting an API to my xamarin app.
When I try to call the API visual studio & the app do not give a response.
Visual studio keeps running but nothing happens.
I've changed the firewall settings, and set my IP adres in all the desired places. Still not luck.
If I go to my API using swager or postman and I just the same Uri as I want to pass trough with my app I get the correct response.
What could be the reason for this?
my code:
Material service:
private readonly string _baseUri;
public APIMaterialService()
{
_baseUri = "https://192.168.1.9:5001/api";
}
public async Task<Material> GetById(Guid id)
{
return await WebApiClient
.GetApiResult<Material>($"{_baseUri}/Materials/{id}");
}
WebApiClient:
public class WebApiClient
{
private static HttpClientHandler ClientHandler()
{
var httpClientHandler = new HttpClientHandler();
#if DEBUG
//allow connecting to untrusted certificates when running a DEBUG assembly
httpClientHandler.ServerCertificateCustomValidationCallback =
(message, cert, chain, errors) => { return true; };
#endif
return httpClientHandler;
}
private static JsonMediaTypeFormatter GetJsonFormatter()
{
var formatter = new JsonMediaTypeFormatter();
formatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return formatter;
}
public async static Task<T> GetApiResult<T>(string uri)
{
using (HttpClient httpClient = new HttpClient(ClientHandler()))
{
//Gets stuck finding the response
string response = await httpClient.GetStringAsync(uri);
return JsonConvert.DeserializeObject<T>(response, GetJsonFormatter().SerializerSettings);
}
}
I'll also add some images of the postman and swager response:
This is the code fo my controller.
return OK (material) shows me the data retrieved from the API
public async Task<IActionResult> GetMaterialByPartOfMaterialNumberOP(string partOfMaterialNumber)
{
var material = await _materialService.GetMaterialListbyPartOfMaterialNumber(partOfMaterialNumber);
return Ok(material);
}
The symptom you have (stuck on result from calling a method of HttpClient class) suggests a deadlock.
I believe the deadlock happens if you create multiple instances of HttpClient.
Doc HttpClient Class says:
// HttpClient is intended to be instantiated once per application, rather than per-use. See Remarks.
And shows this code:
static readonly HttpClient client = new HttpClient();
HOWEVER a deadlock would only happen the SECOND time your code does new HttpClient. And using ... new HttpClient should protect you, at least in simple situations.
Here are ways there might be TWO HttpClients active:
Is it possible that GetApiResult gets called A SECOND TIME, before the first one finishes?
Does your app do new HttpClient ELSEWHERE?
Here is what the technique might look like in your app:
public class WebApiClient
{
static HttpClient _client = new HttpClient(ClientHandler());
public async static Task<T> GetApiResult<T>(string uri)
{
string response = await _client.GetStringAsync(uri);
return JsonConvert.DeserializeObject<T>(response, GetJsonFormatter().SerializerSettings);
}
}

Asp.Net Core Cannot access a disposed context instance

I'm trying to implement SignalR in order to consume data from a angular frontend application.
I've checked all the results on google that I can find, but I still can't solve my issue.
The error I'm getting is:
Cannot access a disposed context instance. A common cause of this
error is disposing a context instance that was resolved from
dependency injection and then later trying to use the same context
instance elsewhere in your application. This may occur if you are
calling 'Dispose' on the context instance, or wrapping it in a using
statement. If you are using dependency injection, you should let the
dependency injection container take care of disposing context
instances. Object name: 'AdminContext'
Controller
[Route("api/[controller]")]
[ApiController]
public class ChartController : ControllerBase
{
private IHubContext<ChartHub> _hub;
private readonly ILiveMonitoringService _service;
public ChartController(IHubContext<ChartHub> hub, ILiveMonitoringService service)
{
_hub = hub;
_service = service;
}
public IActionResult Get()
{
var timerManager = new TimerManager(async () => await _hub.Clients.All.SendAsync("transferchartdata", await _service.GetAllAsync()));
return Ok(new { Message = "Request Completed" });
}
}
Service
public Task<List<LiveMonitoring>> GetAllAsync()
{
return _repository.GetAll().Take(100).ToListAsync();
}
Repository
public IQueryable<TEntity> GetAll()
{
try
{
return _adminContext.Set<TEntity>();
}
catch (Exception ex)
{
throw new Exception("Couldn't retrieve entities");
}
}
What could be the problem?
I'm pretty sure that TimerManager is your issue. You did not show its declaration but looks like its constructor accepts a callback to be called at some later point of time. And that's the issue. Your scoped service _service is captured in the callback and used at some later point of time when the request has already ended. So after the request ended, the DbContext is disposed and your _service will consume a disposed context.
The fix is to simply get the data first before passing it into your callback so that the _service will not be captured into that callback, like this:
public async Task<IActionResult> Get()
{
var liveMonitorings = await _service.GetAllAsync();
var timerManager = new TimerManager(async () => await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings));
return Ok(new { Message = "Request Completed" });
}
We need to change the returned type of Get to Task<IActionResult> to support async call.
If you actually want to call _service.GetAllAsync() at some time later (not at the time of requesting Get) inside the callback, you need to inject an IServiceScopeFactory to create a scope for your service inside that callback, like this:
public IActionResult Get([FromServices] IServiceScopeFactory serviceScopeFactory)
{
var timerManager = new TimerManager(async () =>
{
using(var scope = serviceScopeFactory.CreateScope()){
var service = scope.ServiceProvider.GetRequiredService<ILiveMonitoringService>(); ​
​var liveMonitorings = await service.GetAllAsync();
​return await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings);
​ }
​});
​return Ok(new { Message = "Request Completed" });
}
This way you don't need to inject your _service into the controller's constructor (because it's not used at all).
​

How to use Realm Collection Notifications in an ASP.NET Core Application?

I've tried using this sample code from the Realm .NET SDK but my handler code never gets called consistently:
var token = realm.All<Person>().SubscribeForNotifications ((sender, changes, error) =>
{
// Access changes.InsertedIndices, changes.DeletedIndices, and changes.ModifiedIndices
});
I've tried running this from a number of different threads, but I suspect none of them have a looper/runloop, a requirement noted in the SDK. Is it even possible to create a looper/runloop thread in ASP.NET Core that will work with Realm? How would I do that?
Finally figured out how to implement the looper/run loop that works for Realm Notifications. The keys parts of the solution are:
Use a hosted service to start/stop the thread.
Use Nito.AsyncEx to establish a synchronization context for that thread.
Loop inside the thread, calling the RefreshAsync method on the realm instance.
Call Task.Delay between loop iterations to keep the thread cpu-friendly.
Here is the code:
public class RealmNotificationService : IHostedService
{
private System.Threading.Thread _thread;
public Task StartAsync(CancellationToken stoppingToken)
{
_thread = new System.Threading.Thread(() =>
Nito.AsyncEx.AsyncContext.Run(() => Looper(stoppingToken))
);
_thread.Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken stoppingToken)
{
return Task.CompletedTask;
}
private async void Looper(CancellationToken stoppingToken)
{
using (var connection = await Realm.GetInstanceAsync({YOUR-CONFIG}))
{
var token = connection.All<{YOUR-OBJECT}>().SubscribeForNotifications((sender, changes, error) =>
{
// Access changes.InsertedIndices, changes.DeletedIndices, and changes.ModifiedIndices
});
}
while (!stoppingToken.IsCancellationRequested)
{
await connection.Realm.RefreshAsync();
await Task.Delay(2000, stoppingToken);
}
}
}
Bill Raudabaugh's answer almost worked for me. However, the final while loop is outside of the using so connection is undefined.
I was able to get it to work by moving that loop inside of the using. Also I removed the RefreshAsync() as it seems it's not needed; Realm automatically updates in real time without having to refresh.
Here is my code:
public class RealmNotificationService : IHostedService
{
private System.Threading.Thread _thread;
public Task StartAsync(CancellationToken stoppingToken)
{
_thread = new System.Threading.Thread(() =>
Nito.AsyncEx.AsyncContext.Run(() => Looper(stoppingToken))
);
_thread.Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken stoppingToken)
{
return Task.CompletedTask;
}
private async void Looper(CancellationToken stoppingToken)
{
using (var connection = await Realm.GetInstanceAsync({YOUR-CONFIG}))
{
var token = connection.All<{YOUR-OBJECT}>().SubscribeForNotifications((sender, changes, error) =>
{
// Access changes.InsertedIndices, changes.DeletedIndices, and changes.ModifiedIndices
});
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(2000, stoppingToken);
}
}
}
}

How to change api return result in asp.net core 2.2?

My requirement is when the return type of the action is void or Task, I'd like to return my custom ApiResult instead. I tried the middleware mechanism, but the response I observed has null for both ContentLength and ContentType, while what I want is a json representation of an empty instance of ApiResult.
Where should I make this conversion then?
There are multiple filter in .net core, and you could try Result filters.
For void or Task, it will return EmptyResult in OnResultExecutionAsync.
Try to implement your own ResultFilter like
public class ResponseFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// do something before the action executes
if (context.Result is EmptyResult)
{
context.Result = new JsonResult(new ApiResult());
}
var resultContext = await next();
// do something after the action executes; resultContext.Result will be set
}
}
public class ApiResult
{
public int Code { get; set; }
public object Result { get; set; }
}
And register it in Startup.cs
services.AddScoped<ResponseFilter>();
services.AddMvc(c =>
{
c.Filters.Add(typeof(ResponseFilter));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
All you have to do is to check the return type and on the basis of the return you can perform whatever operations you want.
Here is the abstract demo:
You have a method:
public Action SomeActionMethod()
{
var obj = new object();
return (Action)obj;
}
Now in your code you can use the following code to get the name of the method:
MethodBase b = p.GetType().GetMethods().FirstOrDefault();
var methodName = ((b as MethodInfo).ReturnType.Name);
Where p in the above code is the class which contains the methods whose return type you want to know.
after having the methodname you can decide on variable methodName what to return.
Hope it helps.

AspNetCore.SignalR SendAsync not firing inside OnConnectedAsync

I am having an issue where I would like to send an event to the frontend whenever somebody is connected to the hub, but the notification is not being received on the front end. I think I may be confused between calling methods directly from the hub vs. utilizing the IHubContext. I was not able to find much information related to these versions, so your help will be greatly appreciated!
Package versions:
Server side (.Net Core 2.2): Microsoft.AspNetCore.SignalR (1.1.0)
Client side (React): #aspnet/signalr:1.1.0
So this is my example Hub:
public class MyHub: Hub<IMyHub>
{
public override async Task OnConnectedAsync()
{
// This newMessage call is what is not being received on the front end
await Clients.All.SendAsync("newMessage", "test");
// This console.WriteLine does print when I bring up the component in the front end.
Console.WriteLine("Test");
await base.OnConnectedAsync();
}
public Task SendNewMessage(string message)
{
return Clients.All.SendAsync("newMessage", message);
}
}
Now the working call I have so far is in a service, but that is sending "newMessage" like so:
public class MessageService: IMessageService
{
private readonly IHubContext<MyHub> _myHubContext;
public MessageService(IHubContext<MyHub> myHubContext)
{
_myHubContext = myHubContext;
}
public async Task SendMessage(string message)
{
// I noticed tis calls SendAsync from the hub context,
// instead of the SendMessage method on the hub, so maybe
// the onConnectedAsync needs to be called from the context somehow also?
await _myHubContext.Clients.All.SendAsync("newMessage", message);
}
}
So the above service method call works and will contact the front end, this is an example of my front end connection in a react component:
const signalR = require('#aspnet/signalr');
class MessageComponent extends React.Component {
connection: any = null;
componentDidMount() {
this.connection = new signalR.HubConnectionBuilder()
.withUrl('http://localhost:9900/myHub')
.build();
this.connection.on('newMessage', (message: string) => {
// This works when called from the service IHubContext
// but not OnConncectedAsync in MyHub
console.log(message);
});
this.connection.start();
}
componentWillUnmount() {
this.connection.stop();
}
render() {
...
}
}
This is because you are using a Strongly Typed Hub (https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-2.2#strongly-typed-hubs).
I assume you defined SendAsync on your IMyHub interface and so the server is sending a message with method = SendAsync, arguments = "newMessage", "test". If you removed your IMyHub type then this will work as expected.