I been working on a proxy-like controller on ASP.NET, it takes URL from incoming request and uses HttpClient to call the URL, then return the file.
This proxy-like controller work like this:
Works fine when executing one request
Works fine when executing multiple requests,those responses have content-type of "application/json" and "xml"
Request Time-out on 2nd request and Task Cancelled when executing 4 requests, those responses have content-type of "image/png". Like following:
(These 4 request are being sent to controller almost at the same time).
Request 1 - start at 0s , finished at 1s
Request 2 - start at 1s ,Time out and exception throw at 11:00(Time out is 10s), server hangs until timeout
Request 3 - start at 11s , finished at 12s
Request 4 - start at 12s , finsihed at 13s
Please Ignore the POST Situation
Controller
public async Task<FileStreamResult> Proxy(string method, string url, string data = "")
{
myHttpClient client = new myHttpClient();
Tuple<MemoryStream,string> result = await client.Proxy(this.Request, method, url).ConfigureAwait(false);
return File(result.Item1,result.Item2); //file stream and file type
}
HttpClient
public class myHttpClient
{
private static HttpClient _httpClient;
static myHttpClient()
{
if (_httpClient == null) {
_httpClient = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
_httpClient.Timeout = TimeSpan.FromSeconds(7);
Log ocLog = new Log();
ocLog.Write("init client " + ServicePointManager.DefaultConnectionLimit ,false);
}
}
public async Task<Tuple<MemoryStream, string>> Proxy(HttpRequestBase contextRequest, string method, string url)
{
var request = new HttpRequestMessage();
request.RequestUri = new Uri("http://localhost" + url);
if (method == "GET")
{
request.Method = HttpMethod.Get;
request.Content = null;
}
else if (method == "POST")
{
request.Method = HttpMethod.Post;
}
//copy request header from context.Request
foreach (string headerName in contextRequest.Headers)
{
string[] headerValues = contextRequest.Headers.GetValues(headerName);
if (!request.Headers.TryAddWithoutValidation(headerName, headerValues))
{
request.Content.Headers.TryAddWithoutValidation(headerName, headerValues);
}
}
try
{
using (HttpResponseMessage response = await _httpClient.SendAsync(request).ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
var contentBytes = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
MemoryStream ms = new MemoryStream(contentBytes);
return new Tuple<MemoryStream, string>(ms, response.Content.Headers.ContentType.ToString());
}
else
{
return null;
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
What have i tried
Checking ServicePointManager.DefaultConnectionLimit. It is very large.
Use System.net.WebRequest library instead of HttpClient, still the same.
The problem has been solved by setting the "Maximum Process Workers" of the application pool to 3. It did the trick
Related
So I have to API's running on Kubernetes. One has a controller function as such:
string filePath = "/blobs/data/runsession/" + folderName;
if (!Directory.Exists(filePath))
return null;
var tempFile = Path.Combine(Path.GetTempPath(), guid.ToString());
logger.Info("GetTempPath()" + Path.GetTempPath());
logger.Info("Temp path is: " + tempFile);
ZipFile.CreateFromDirectory(filePath, (tempFile + ".zip"));
byte[] fileBytes = File.ReadAllBytes(tempFile + ".zip");
HelpMethods.GetNetworkTimeStamp("Stop", 2);
return fileBytes;
This controller method works fine and when I call it from postman it returns a file.
Now in the other API I want to call this function from one of my service classes as such:
public async Task<byte[]> DownloadRunSession(string foldername)
{
try
{
var request = new RestRequest($"blob/{foldername}")
{
Timeout = -1,
};
var response = await client.ExecuteGetAsync(request);
if (!response.IsSuccessful)
{
Console.WriteLine("File download failed");
Console.WriteLine(response.Content.ToString());
return null;
}
return response.RawBytes;
}catch(Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
return null;
}
Now the server logs on the API that sends the file Give me a status 200 but says "the application aborted the connection", and the API that is supposed to receive the file gets no response and the response variable is always "null".
Any one that has had a similar dilemma and knows how to solve it?
I want to accept http request to order prefab move, so how to receive http request in unity 3D?
If you mean you want to build a web service in your Unity app.
RESTful-Unity is an easy-to-use plugin.
Define the api routing
RoutingManager routingManager = new RoutingManager();
routingManager.AddRoute(new Route(Route.Type.POST, "/path/to/call", "PrefabInvoke.Move"));
Create an Invoke to response the request
namespace RESTfulHTTPServer.src.invoker
{
public class PrefabInvoke : MonoBehaviour
{
public static Response Move(Request request)
{
Response response = new Response();
string responseData = "";
string json = request.GetPOSTData();
bool valid = true;
UnityInvoker.ExecuteOnMainThread.Enqueue (() => {
Debug.Log(json);
try
{
//TODO: Parse Json string and do somthing
response.SetHTTPStatusCode((int)HttpStatusCode.OK);
responseData = "sucess message";
}
catch (Exception ex)
{
valid = false;
string msg = "failed to deseiralised JSON";
responseData = msg;
}
});
// Wait for the main thread
while (responseData.Equals("")) {}
// Filling up the response with data
if (valid) {
// 200 - OK
response.SetContent(responseData);
response.SetHTTPStatusCode ((int)HttpStatusCode.OK);
response.SetMimeType (Response.MIME_CONTENT_TYPE_JSON);
} else {
// 406 - Not acceptable
response.SetContent("Somthing wrong");
response.SetHTTPStatusCode((int) HttpStatusCode.NotAcceptable);
response.SetMimeType(Response.MIME_CONTENT_TYPE_HTML);
}
return response;
}
}
}
This is the exact exception in the error logs.
I have a requirement where I should be creating a set of service calls and wait till all of them are completed successfully before moving on to do a different set of service calls.
I have two services Service1 and Service2.
There are 2 instances of Service2 in 2 different servers and we have set up an F5(Load Balancer) to distribute the load evenly.
Let's say I have 10 service calls to be made from Service1 to Service2 at a time and F5 will share those 10 calls among the 2 servers. i.e. 5 Calls to Service2 of each server.
But I observed that if any one of those 10calls is taking lot of time to complete the work it should do(The work to be done in Service2 has some heavy lifting) then i get a socket exception thrown and entire process gets stopped.
However when I dont use the F5 load balancer and just use 1 instance of the Service2. Then however long the process takes for any of those 10 calls it doesn't throw any exception.
I am not sure if this is an issue with F5 configuration or with the way connections are made with the F5 from .Net code.
Please go through the below code to get some idea of what i am trying to do and let me know if any code change would help me resolve it.
for (int i=0 ; i< ReqList.Count;i++)
{
maxTasks++;
ClassA reqList = new ClassA();
reqList = ReqList[i];
List<ClassA> recsByReq = recs.Where(x => x.ReqId == reqList.ReqtId).ToList();
ClassC service2Input = new ClassC();
service2Input.DetaiList = listofRecs;
service2Input.RecList = recsByReq;
taskList.Add(_service2.Service2MethodCall(service2Input, service2Resource));
if(maxTasks == 10 || ReqList.Count == 10 || i==ReqList.Count-1)
{
Task.WaitAll(taskList.ToArray(),-1);
maxTasks = 0;
taskList.Clear();
}
}
The Service2MethodCall is where I am creating a HttpClient to make connections with the 2nd service i.e. Service2,
public class Service2: IService2 {
private ServiceClient GetService2(string resource)
{
return new ServiceClient(_service2BaseUrl, TimeSpan.FromMinutes(60))
{
Resource = resource,
};
}
public async Task Service2MethodCall(ClassC service2Input, string resource)
{
try
{
var client = GetService2(resource);
await client.PostAsync(JsonConvert.SerializeObject(service2Input).ToString());
}
catch (Exception ex)
{
throw new Exception("The Service encountered an error during the Service2 call for Req ID : " +
service2Input.RecsList.Find(x => x.ReqId != "").ReqId.ToString(), ex);
}
}
}
The PostAsync() method creates a new HttpClient with HttpClientHandler object for each of the call.
public async Task PostAsync(object data) {
using(var httpClientHandler = new HttpClientHandler()) {
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => {
if (sslPolicyErrors == SslPolicyErrors.None) {
return true; //Is valid
}
if (cert.GetCertHashString().ToUpper() == _acceptedThumbprint.ToUpper()) {
return true;
}
return false;
};
using(var client = new HttpClient(httpClientHandler)) {
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(ResponseFormatter.MediaType);
client.Timeout = Timeout.InfiniteTimeSpan;
Uri uri = BuildUri();
if (!String.IsNullOrWhiteSpace(SignatureKey)) {
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization",
RequestFormatter.GenerateAuthHeaderEncodedUserSignature(uri, AuthUserName, SignatureKey, data));
}
//_logger.WriteUsage(client.BaseAddress.ToString());
HttpResponseMessage response = await RequestFormatter.PostAsync(client, uri, data);
string content = await response.Content.ReadAsStringAsync();
try {
response.EnsureSuccessStatusCode();
}#
pragma warning disable CS0168 // The variable 'rex' is declared but never used
catch (HttpRequestException rex)# pragma warning restore CS0168 // The variable 'rex' is declared but never used
{
//_logger.WriteUsage("Response for POST to: {0} did not yield a successful status code. Message: {1}" + uri.ToString() + content);
throw new ApiHttpException(response.StatusCode, content);
}
}
}
}
Is there some thing I can do within the code to avoid this situation once and for all?
I use HttpClient object for PostAsync. I need to add BackgroundSessionConfiguration for iOS while I am creating HttpClient object. So I changed my code like this:
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration ("my.app.identifier");
_client = new HttpClient (new NSUrlSessionHandler (configuration));
This works when I send first request with PostAsync. But when I send request second time, it doesn't work.
I did it for Login Operation like this: (It works first time but if I logout and login again, it doesn't work.)
public class LoginService
{
private HttpClient _client;
public LoginService()
{
if (_client == null)
{
_client = Helper.CreateHttpClientLogin(_client);
}
}
public async Task<LoginResponse<LoginDataResponse>> Login(LoginRequest request)
{
LoginResponse<LoginDataResponse> responseModel = new LoginResponse<LoginDataResponse>();
try
{
string json = JsonConvert.SerializeObject(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var jsonBody = await _client.PostAsync(App.ServiceURL.Login_Url, content);
string jsonstr = await jsonBody.Content.ReadAsStringAsync();
if (jsonstr == null || jsonstr == "")
{
responseModel.Success = false;
responseModel.Status = 0;
responseModel.Message = AppResources.UnknownHostException;
}
else
responseModel = (LoginResponse<LoginDataResponse>)JsonConvert.DeserializeObject(jsonstr, typeof(LoginResponse<LoginDataResponse>));
}
catch (Exception ex)
{
string text = ex.ToString();
responseModel.Status = 0;
AppResources.Culture = CrossMultilingual.Current.CurrentCultureInfo;
responseModel.Message = AppResources.UnknownHostException;
}
return responseModel;
}
}
public class Helper
{
public static HttpClient CreateHttpClientLogin(HttpClient _client)
{
if (Device.RuntimePlatform == Device.iOS)
{
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration("my.app.identifier");
_client = new HttpClient(new NSUrlSessionHandler(configuration));
}
else
{
//_client = new HttpClient(new System.Net.Http.HttpClientHandler());
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
_client = new HttpClient(handler);
}
return _client;
}
}
And I have this code on AppDelegate: (I don't know but maybe it causes the bug)
public static Action BackgroundSessionCompletionHandler;
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler)
{
// We get a completion handler which we are supposed to call if our transfer is done.
BackgroundSessionCompletionHandler = completionHandler;
}
What must I do for this?
Edit:
I solved the problem I mentioned above by creating the Login Service object once the application was first opened. (After logout previously, I was rebuilding every time I login)
But now I have other error. When I run my app on "iPhone 7 plus - iOS 13.6" device I got this error:
System.Net.Http.HttpRequestException: unknown error ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSErrorFailingURLStringKey=https://mydomain/Api/Login, NSErrorFailingURLKey=https://mydomain/Api/Login, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundDataTask <E69F3EAF-0AE9-4FAE-A01B-988167B7F6BC>.<3>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDataTask <E69F3EAF-0AE9-4FAE-A01B-988167B7F6BC>.<3>, NSLocalizedDescription=unknown error}
--- End of inner exception stack trace ---
at System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x001d4] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.20.2.2/src/Xamarin.iOS/Foundation/NSUrlSessionHandler.cs:527
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506
at App.Services.LoginService.Login (FileOrbis.Models.RequestModels.LoginRequest request) [0x00084] in C:\Users\PcName\Desktop\App\App\Services\LoginService.cs:40
And simulator log file is:
Startup:
arguments: --device=06098E5B-1853-4A83-8434-8071D8973A14 --launchsim=//Users/deytek/Library/Caches/Xamarin/mtbs/builds/App.iOS/b2c75f2acbd4ff91c305dba10ca791b7/bin/iPhoneSimulator/Debug/App.iOS.app -argument=-monodevelop-port -argument=51890 -setenv=__XAMARIN_DEBUG_PORT__=51890 --sdkroot=/Applications/Xcode.app -h=192.168.1.7 -ssh=deytek --launched-by=devenv-16.0
version: 16.7.0.0 (54a29526ef6f853bdd37adbcc3791ce90ca82735)
Connecting to existing client
Exit:
Exit Code: 0
I encounter with this error when I use Background Session Configuration. If I use normal HttpClient object (without Background Session Configuration), it works
NOTE: I also tried iPhone 5s iOS 12.4.8 and iPad Pro (3rd Generation) iOS 13.6.1 It works these devices. But it doesn't work on iPhone 7 Plus 13.6
I use the following rest client implementation of jersey to consume a rest service.I am able to do it successfully.Additionally now I need to send request parameters which will be consumed as part of HttpServletRequest on the producer side.
Consumer side Jersey client code
private ClientResponse getWebClientResponse(String RESOURCE_PATH, String methodType, Object requestObj) {
WebResource webResource;
ClientResponse response = null;
try {
String environmentHost = EnvironmentUtil.resolveEnvironmentHost();
Client client = prepareClient();
String RWP_BASE_URI = environmentHost + "/workflow/rest";
webResource = client.resource(RWP_BASE_URI);
WebResource path = webResource.path(RESOURCE_PATH);
if (GET.equals(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(
ClientResponse.class);
} else if (POST.equalsIgnoreCase(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).post(ClientResponse.class, requestObj);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return response;
}
Producer side
#Context
public void setContext(SecurityContext context) {
this.context = context;
}
public HttpServletRequest getRequest() {
return request;
}
#Context
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public String getSessionUserPID(final HttpServletRequest request,
final SecurityContext context) {
if (request.getSession(false) == null) {
final String exceptionMessage = "getSessionUserPID() failed, session NOT FOUND for this request";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
if (context.getUserPrincipal() == null) {
final String exceptionMessage = "getSessionUserPID() failed, user principal NOT FOUND";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
final String userPID = context.getUserPrincipal().getName();
if (userPID == null || userPID.isEmpty()) {
final String exceptionMessage = "getSessionUserPID() failed, user principal name cannot be null or empty";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
return userPID;
}
The main intention here is currently I get user information from weblogic security context but for a particular scenario I need to pass this part of rest service request and obtain it from HttpServletRequest object.How can I obtain this from httpservletrequest
You can use QueryParam or PathParam in GET method and FormParam in the POST method for sending request parameter to the server.