We have an MVC5 SPA application where one of our Web API controllers needs to process the import of a file. This process is made once per month, and can take up to 5 hours (our client wants this import to be made via Web API).
Our problem is that the connection is lost (ERR_CONNECTION_RESET) after one hour, and we need to keep it opened during the entire process.
We think one option is to send partial content from the server, to let the browser know the connection is still active and processing. In MVC Controller, something like this:
public class PartialActionResult : ActionResult
{
private Counter _counter;
private Action<Counter> _counterIncrease;
public PartialActionResult(Action<Counter> counterIncrease)
{
_counter = new Counter();
_counterIncrease = counterIncrease;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "text/html";
context.HttpContext.Response.BufferOutput = true;
if (context.HttpContext.Response.IsClientConnected)
{
while (_counter.Value < 100)
{
_counterIncrease(_counter);
context.HttpContext.Response.Write("processing...");
if (_counter.Value == 100)
context.HttpContext.Response.Write("OK");
context.HttpContext.Response.Flush();
}
}
}
}
With this, we can pass a delegate as reference, and from there we can update the information of the import status.
Is there any option for Web API, as this ActionResult only works for MVC Controllers? Other than that, any option to maintain the connection opened? BTW we cannot use signalR, just in case that might work.
Thanks in advance
Related
I am facing worst & awkward issue of my life.
I am using HttpActionExecutedContext for caching my WEB API end points.
My web API is working properly in case of caching, but when I have updated the data & at that time I wanted to reset the caching at that time problem is arises.
Problem 1 :-
When I have deleted the bin folder from the server, then also API was sending the data to me.
(I have consumed API in ANDROID phone, I have tested in 2 phones after deleting the BIN bolder, In 1st phone API was giving data even after BIN DELETION & in 2nd phone API was giving partial data such as 1 end point was working but another was not).
How can this be possible ?
Problem 2 :-
Where data is saved when we use HttpActionExecutedContext. Wheather data is saved application pool or something ?
Problem 3 :-
How to clear the cache of WEB API.
Here is the code of WEB API.
public class CacheFilter : ActionFilterAttribute
{
public int TimeDuration { get; set; }
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
{
MaxAge = TimeSpan.FromMinutes(1440),
MustRevalidate = true,
Public = true
};
}
}
Controller Code
[HttpGet]
[Route("SubCategory")]
[CacheFilter()]
public string SubCategory()
{
BAL_CAT_ALL obj = new BAL_CAT_ALL();
var data = obj.GetAllSubCategory();
return data;
}
While issuing a request to server when the data has been updated , can you please add the below 2 headers in your request:-
'Cache-Control', 'no-cache' 'Pragma', 'no-cache'
Give it a try and let us know if the issue is resolved or ?
I am very new with orleans and trying to grasp everything with grains and so forth.
What i got is that in my startup.cs file i add the SignalR like this
public IServiceProvider ConfigureServices(IServiceCollection services)
{
Program.WriteConsole("Adding singletons");
services
.AddSingleton(achievementManager)
.AddMvc();
services.AddSingleton(SignalRClient);
return services.BuildServiceProvider();
}
So far everything is fine i can start my host/application and it connects to SignalR as it should. But what i cant wrap my head around is how do i get this down to my grain? if i had a controller i would simply send it down in the constructor on startup but how do i do this with a grain? Or can i even do it like this. Any guidance is appreciated.
In the grain then i want to do something like this
[StatelessWorker]
[Reentrant]
public class NotifierGrain : Grain, INotifierGrain
{
private HubConnection SignalRClient { get; }
public NotifierGrain(HubConnection signalRClient)
{
SignalRClient = signalRClient;
SignalRClient.SendAsync(Methods.RegisterService, Constants.ServiceName);
}
public Task NotifyClients(object message, MessageType type)
{
var registerUserNotification = (RegisterUserNotificationModel)message;
SignalRClient.SendAsync(Methods.RegisterUserToMultipleGroups, registerUserNotification.UserId, registerUserNotification.InfoIds);
}
return Task.CompletedTask;
}
Then i try to call the Notify method from another grain like this
var notifier = GrainFactory.GetGrain<INotifierGrain>(Constants.NotifierGrain);
await notifier.NotifyClients(notification, MessageType.RegisterUser);
But trying to do this ends up with an error like this
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.Client.HubConnection' while attempting to activate 'User.Implementation.Grains.NotifierGrain'.
Orleans supports constructor injection, so you can inject the SignalRClient into your grain constructor. In your code you are already correctly registering the client using services.AddSingleton(SignalRClient), so I will focus on how to inject the type into your grain.
I do not know what the type the SignalR client object is, but in this example I assume that the type is "SignalRClient":
[StatelessWorker]
[Reentrant]
public class NotifierGrain : Grain, INotifierGrain
{
private readonly SignalRClient signalRClient;
public NotifierGrain(SignalRClient signalRClient)
{
this.signalRClient = signalRClient;
}
public async Task NotifyClients(object message, MessageType type)
{
var registerUserNotification = (RegisterUserNotificationModel)message;
await this.signalRClient.SendAsync(
MessageMethods.RegisterUserToMultipleGroups,
registerUserNotification.UserId,
registerUserNotification.infoIds);
}
}
Depends how you're thinking to use SignalR Server, if you're going to host your SignalR server with Microsoft Orleans for sure you need to have backplane to handle the Orleans cluster communications.
You can use SignalR Orleans which has everything done out of the box for you :)
Also if you need a reactive SignalR library for the frontend, you can use Sketch7 SignalR Client
PS I m one of the authors of both libraries.
Below I present a part of an Azure Web App that handles a device notification logic. What I'm doing is invoking the code shown below from a ASP MVC Controller.
But when I run it I get an hung (ever-pending) request from the browser.
I thought I've found a workaround by wrapping the SendAsync call in a BackgroundWorker thread. It's better, but I doesn't work right. For first couple of times (one or two) it works ok, but then it happens again, the wrapped thread hangs.
The code is not far different from the one on MSDN for a console application. What am I missing?
using System.Web.Configuration;
using Microsoft.Azure.Devices;
namespace MyTest
{
public class Sender
{
private readonly string connectionString;
private readonly Microsoft.Azure.Devices.ServiceClient serviceClient;
public Sender()
{
connectionString = WebConfigurationManager.AppSettings["ConnectionString"];
serviceClient = ServiceClient.CreateFromConnectionString(connectionString);
}
public async void SendRequest(string deviceId, string msgText)
{
var message = new Message();
message.Properties.Add("text", msgText));
await serviceClient.SendAsync(deviceId, message);
}
}
}
The problem was caused by inappropriate usage of ASP MVC framework.
It turned out that AsyncController has to be used instead of just Controller when a long running async\await is utilized. The pipeline must be async all the way.
As described in the headline I want to build a Xamarin Forms app which is communicating with a web server. On the client side I am using the MMVM pattern of course.
Here my question: what about the communication with the server? From my point of view the server should nothing know about the concrete client technology (INotifyPropertyChanged e.g), so in this layer I still have to apply the MVC pattern for communication, right?
What costs me sleep on this approach is that I need to convert the objects 2 times in every direction:
Entity <--> MVC-Model (Dto) <--> MVVM-ViewModel
Am I right with my assumption or completely off the track?
One way to achieve this is to create a WebAPI which you then call from your view model in your shared Xamarin Forms project.
public class CommunicationService<T> where T : class
{
public CommunicationService ()
{
}
public async Task<T> GetRequestAsync (string url)
{
var client = new System.Net.Http.HttpClient ();
var response = await client.GetAsync (url);
var responseResult = response.Content.ReadAsStringAsync ().Result;
var result = JsonConvert.DeserializeObject<T> (responseResult);
return result;
}
}
From my view model I then call my function using the code below:
var communicationService = new CommunicationService<List<MyDtoModel>> ();
var items = await communicationService.GetRequestAsync (#"http://myurl.com/api/controller/action");
Then you can use AutoMapper to map the result to your view model, or of course, use the DTO directly, even if that not is best practice for the MVVM pattern.
I use an embedded Grizzly web server to host RESTful web-services with Jersey. This is all working correctly.
My question is how to force the web application context to eagerly initialise when I start the server rather than waiting for the first incoming client request. This is a minor problem, but one I would like to solve.
I start the embedded server like this:
public final class TestApplication {
public TestApplication() throws Exception {
HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(
"http://0.0.0.0:8888",
new ResourceConfig()
.registerInstances(
new TestBinder(),
)
.registerClasses(
JacksonJsonProvider.class,
)
.packages(
AbstractResource.class.getPackage().getName()
),
true
);
}
}
The "TestBinder" configures the dependency injection that I need and that class looks like this:
final class TestBinder extends AbstractBinder {
#Override
protected void configure() {
bind(CatalogManager.class).to(CatalogManager.class).in(Singleton.class);
}
}
Finally, "CatalogManager" is a singleton that is used to pre-load and cache all of the static data that my application exposes via the RESTful web-services.
The essence of "CatalogManager" is this:
public final class CatalogManager {
#PostConstruct
public void initialise() {
// Load and cache a large application data-set here...
}
}
So the problem is that the dependency injection and consequently the #PostConstruct method do not run when the server starts up, instead it waits until the first application request and the first user of my application gets a long delay.