Play framework multiple ajax request - ajax

I have an rest api with Play 2.3.x on a Docker container. This api speak with PostgresSQL 9.4 database (on a Docker container too) and serves JSON. Client is a isomorphic app with React (on Docker container too).
When client change route, several request is send to the api. The problem is that every request is abnormally slow. For example, I have this uri:
GET /api/taxon/185214/geojson
When I send this request directly since the browser, response is shown at the end of 4s. When this request is send with other request, it takes 12s longer.
What can cause this time ?
Of course, every action of api are async. For example, geojson action:
public static Promise<Result> showGeoJson(final Long id)
{
Promise<GeoJsonModel> promise = F.Promise.promise(
new Function0<GeoJsonModel>() {
public GeoJsonModel apply() {
// Get data with ebean
return geojson;
}
}
);
return promise.map(
new Function<GeoJsonModel, Result>() {
public Result apply(GeoJsonModel geojson) {
// return Result
}
}
);
}
Does each request should be treated in another thread ?
EDIT
So, after several tests, it's just my development computer whish is slow. Indeed, on other computer the response time is normal.

Related

PostAsync hanging in Xamarin Forms works on emulator but hangs on actual Mobile phone

I have Xamarin Forms project where I'm trying to POST and GET data to/from a Web API but when I'm making an async/await call, it works on the emulator (not without its original problems!) but when I try it on my actual phone mobile (Samsung S8+), it just hangs indefinitely.
Note that I'm only concentrating on the Android part right now, not iOS, not that the problem should make any difference in either.
This is the code I'm using:
IDataService.cs
Task<TResponse> PostDataAsync<TRequest, TResponse>(string uri, TRequest data)
where TRequest : class
where TResponse : class;
DataService.cs:
public async Task<TResponse> PostDataAsync<TRequest, TResponse>(string
additionalUri, TRequest data)
where TRequest : class
where TResponse : class
{
return await WebClient
.PostData<TRequest, TResponse>
(string.Concat(this.Uri, additionalUri), data);
}
WebClient.cs
using (var client = new HttpClient())
{
var jsonData = JsonConvert.SerializeObject(data);
using (var response = await client.PostAsync(
uri,
new StringContent(jsonData,
Encoding.UTF8,
"application/json" )))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResponse>(content);
}
}
}
Method 1:
LoginPageViewModel.cs
public DelegateCommand SignInCommand => _signInCommand ??
(this._signInCommand = new DelegateCommand(SignInCommandAction));
private async void SignInCommandAction()
{
try
{
....
var user = await this._dataService
.PostDataAsync<LoginRequestDto,
LoginResponseDto>(#"Accounts/Login", loginRequestDto);
....
}
...
}
Method2:
LoginPageViewModel.cs
public DelegateCommand SignInCommand => _signInCommand ??
(this._signInCommand =
new DelegateCommand(async () => await SignInCommandAction()));
private async Task SignInCommandAction()
{
try
{
....
var user = await this._dataService
.PostDataAsync<LoginRequestDto,
LoginResponseDto>(#"Accounts/Login", loginRequestDto);
....
}
...
}
The PostDataAsync works with both methods when I call my local web API i.e. http://10.0.2.2/MyApp/api/ but both methods still hangs when calling external my web service from web provider i.e. http://myapp-123-site.atempurl.com/api/ which is a temp url for testing purpose.
The same apply to my GetDataAsync which is not demonstrated in question but I just thought I'd mention it.
Based on the above, you would think that my async/await code is correct since it works when calling the local web api but then what's causing it to hang when calling the remote web api.
As mentioned, I did enable my INTERNET permission in the manifest.
Any suggestions welcomed?
Thanks.
UPDATE-1:
Note that I've just tried to call a GET opertation within the same function and this is working in the emulator but hanging with the actual mobile.
using (var client = new HttpClient())
{
using (var response = await client.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert
.DeserializeObject<TResponse>(content);
}
}
}
UPDATE-2:
This is somehow working and I have no idea why! The only thing that comes to mind is that I upgraded my libraries. This included PRISM which may have been at the source of the problem but I have no idea.
Sorry I can't provide more details. I could role back my code and try to see if it's hanging again but I just don't have the time to go and experiment some more considering the amount of time I've already spent on this. Sorry.
The requested url is an IP or a domain name.
If it is ip, only the IP of the public network can be accessed by devices on multiple network segments.
If it is a domain name, it needs to support the domain name resolution service.
If you do not have these environments for a while, you need the IP of the device and the IP of the server on the same network segment.
The PostDataAsync works with both methods when I call my local web API i.e. http://10.0.2.2/MyApp/api/ but both methods still hangs when calling external my web service from web provider i.e. http://myapp-123-site.atempurl.com/api/ which is a temp url for testing purpose.
From this phenomenon , the reason should be the temp url. From this domain name (myapp-123-site.atempurl.com) can not find the right local IP (10.0.2.2).And when you test in local network , I guess this will work.However the network of actual mobile can be not the same with local network , such as using 3G/4G network , then this will not working.

WebAPI return 404 on PUT/DELETE operations

This seems to be a fairly common issue, but none of the SO articles I have looked at have solved this for me.
I am working on a ASP.NET WebForms/MVC application running on IIS on Windows 10 (so not IIS Express) which is using jQuery AJAX to invoke a WebAPI application on a separate server. To get around CORS issues, and to add additional processing to all API calls, we implemented a server-side proxy using MVC controllers, so each call would end up somewhere like this:
[HttpPost]
public ActionResult Timesheets_Submit(Timesheet data)
{
var processedData = ProcessTheRequestInSomeWay(data);
var client = new SdkClient();
var results = client.Timesheets.Post(processedData);
return Json(results);
}
And this all worked quite successfully.
However, we are getting rather fed up of having to implement new server-side proxy methods each time we add a new API endpoint, so we decided to create a transparent server-side proxy using WebAPI, and have that do the real work.
The transparent server-side proxy is implemented like this:
public class TransparentProxyDelegatingHandler : DelegatingHandler
{
private static readonly Uri BaseUri = new Uri("https://my.apiserver.com");
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-Forwarded-For", request.GetClientIpAddress());
request.RequestUri = new Uri(BaseUri, request.RequestUri.PathAndQuery.Replace("/Proxy", string.Empty));
ProcessRequestInSomeWay(request);
var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
return response;
}
}
So a request to POST /Proxy/Timesheets will get translated into a call to POST https://my.apiserver.com/Timesheets and the response returned pretty much as-is.
The problem that I am having is that calls which use the PUT and DELETE verbs are being rejected as 404 Not Found by my UI (not by the API, I can still invoke that directly using e.g. Fiddler/Postman); the original proxy used those verbs, so it's not like they haven't been configured, it's just when I'm calling the delegating handler. The handler never gets invoked, so there's something happening in the routing engine that is causing MVC PUT/DELETE requests to work, but WebAPI PUT/DELETE requests to fail.
It turns out I was not registering the TransparentProxyDelegatingHandler correctly; I was registering it like this in my WebApiConfig:
configuration.MessageHandlers.Add(new TransparentProxyDelegatingHandler());
but as it turns out (thanks to https://blog.kloud.com.au/2013/11/24/do-it-yourself-web-api-proxy/), what I really wanted was:
configuration.Routes.MapHttpRoute(name: "proxy", routeTemplate: "proxy/{*path}",
handler: HttpClientFactory.CreatePipeline(
innerHandler: new HttpClientHandler(),
handlers: new DelegatingHandler[]
{
new TransparentProxyDelegatingHandler(),
}),
defaults: new { path = RouteParameter.Optional },
constraints: null);
I'm guessing that what was going on was that because I didn't have any actual ApiController implementations wired up to WebApi, it wasn't resolving correctly somehow in the early stages of the pipeline.

How to get OWIN HttpListener current connections count?

I use OWIN selfhost WebAPI at console application and it use HttpListener.
_owinApplication = WebApp.Start<Startup>(new StartOptions(baseUri));
How i can monitor current active connections in some interval to my application ?
Given the nature of HTTP, it's not really possible to monitor "active" connections, since that concept doesn't really exist in HTTP. A client sends a request to your server, and it either fails, or receives a response.
When you see sites report current active users, that number is usually a qualified guess, or perhaps they monitor the clients with the use of websockets, or some sort of ajax polling.
You can create your own DelegatingHandler, register it in the WebApi pipeline and monitor current connections using overridden SendAsync method:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// TODO: add this request to some static container (like ConcurrentDictionary)
// let the request to be processed
HttpResponseMessage response;
try
{
response = await base.SendAsync(request, cancellationToken);
}
finally
{
// TODO: remove the request from the static container registered above
}
// return the response
return response;
}
This way you can not only monitor current connection count, but also all request information, like URL, IP, etc.
I'm create custom middleware and it solve my problem

How to set up Web API Routing for a Proxy Controller?

Part of my application needs to act as a Proxy Server for a third party RESTful web service. Is there a way to set up Web API routing so that all requests of the same type will go to the same method?
For example, if the client sends in either of these GET requests I want them to go into a single GET action method that then sends on the request to the downstream server.
api/Proxy/Customers/10045
api/Proxy/Customers/10045/orders
api/Proxy/Customers?lastname=smith
The single action method for GET would pick up any one of these three requests and send them on to the respective service (I know how to work with HttpClient to make that happen effectively):
http://otherwebservice.com/Customers/10045
http://otherwebservice.com/Customers/10045/orders
http://otherwebservice.com/Customers?lastname=smith
I don't want to have to tightly couple my web service to the third party web service and replicate their entire API as method calls inside mine.
One workaround that I have thought of is to simply encode the target URL in JavaScript on the client and pass this into the Web API which will then only see one parameter. It would work, but I'd prefer to use the routing capabilities in Web API if possible.
Here's how I got this to work. First, create a controller with a method for each verb you want to support:
public class ProxyController : ApiController
{
private Uri _baseUri = new Uri("http://otherwebservice.com");
public async Task<HttpResponseMessage> Get(string url)
{
}
public async Task<HttpResponseMessage> Post(string url)
{
}
public async Task<HttpResponseMessage> Put(string url)
{
}
public async Task<HttpResponseMessage> Delete(string url)
{
}
}
The methods are async because they're going to use an HttpClient. Map your route like this:
config.Routes.MapHttpRoute(
name: "Proxy",
routeTemplate: "api/Proxy/{*url}",
defaults: new { controller = "Proxy" });
Now back to the Get method in the controller. Create an HttpClient object, create a new HttpRequestMessage object with the appropriate Url, copy everything (or almost everything) from the original request message, then call SendAsync():
public async Task<HttpResponseMessage> Get(string url)
{
using (var httpClient = new HttpClient())
{
string absoluteUrl = _baseUri.ToString() + "/" + url + Request.RequestUri.Query;
var proxyRequest = new HttpRequestMessage(Request.Method, absoluteUrl);
foreach (var header in Request.Headers)
{
proxyRequest.Headers.Add(header.Key, header.Value);
}
return await httpClient.SendAsync(proxyRequest, HttpCompletionOption.ResponseContentRead);
}
}
The URL combining could be more sophisticated, but that's the basic idea.
For the Post and Put methods, you'll also need to copy the request body
Also please note a HttpCompletionOption.ResponseContentRead parameter passed in SendAsync call, because without it, ASP.NET will spend an exremeley long time reading the content if the content is large (in my case, it changed a 500KB 100ms request into a 60s request).

What is the proper way to add Timer (for Task Schedule) in Spring 3+Tiles based web application?

I want to know if there is any proper way to add timer for task schedule (it will be count up) in Spring 3 + Tiles that works accurate. I have tried many options like jquery timer + (Client side) Quartz (Server side Threading), But though it is not accurate and somewhat we can say it is bad practice for web application.
What I exactly want (want to manage) is in my Web application(Spring 3 + Tiles), When user Click on Timer start, It should be started at client side and timer should be continued until user click on stop, however user could do any other things (Like navigation to any other pages) in web application but timer should be working in static way. There are many issues as if only I implement timer at client side (using cookies ,jquery session client side) than I have to manage if user navigate to another page then again timer will have to start from previous time that has been stored in cookies but doing this results in loss of seconds during request response processes.So I tried also to implement server side timer using quartz but again I have to sync it with client side timer at every click in web application . So again it is bad practice what I feel.
So Is there any thing that I can introduce in Spring 3 + tiles that can be static and can hold timer in static way.
Thanx in Advance.
Ok so you need Server Push in simple words.You can use Atmosphere for acheving this.
For integrating atmosphere with Spring MVC you can check this sample spring-web-mvc-atmosphere.after integration you just need to do this on your server side.
#RequestMapping(value = "/websockets", method = RequestMethod.GET)
#ResponseBody
public void websockets(final AtmosphereResource event) {
AtmosphereUtils.suspend(event);
final Broadcaster bc = event.getBroadcaster();
bc.scheduleFixedBroadcast(new Callable<String>() {
public String call() throws Exception {
return (new Date()).toString();
}
}, 1, TimeUnit.SECONDS);
}
And from client side:
function startTimer() {
var callbackAdded = false;
function callback(response)
{
$.atmosphere.log('info', ["response.state: " + response.state]);
$.atmosphere.log('info', ["response.transport: " + response.transport]);
if (response.transport != 'polling' && response.state != 'connected' && response.state != 'closed') {
$.atmosphere.log('info', ["response.responseBody: " + response.responseBody]);
if (response.status == 200) {
var data = response.responseBody;
if (data) {
$("#date").text(data);
}
}
}
}
$.atmosphere.subscribe("${pageContext.request.contextPath}/user/websockets",
!callbackAdded? callback : null,
$.atmosphere.request = {transport: 'websocket'});
connectedEndpoint = $.atmosphere.response;
callbackAdded = true;
};
Just suspend the get request and broadcast the current time perodically and you can extend this according to you need I have just given you a raw idea.Hope this helps.

Resources