Xamarin Portable Class Library Gets Proxy Access Denied on iPhone Simulator - cross-platform

I've run into a bit of an issue with the iPhone simulator when trying to access a WCF REST service.
I've asked the question on the Xamarin forums, but no joy.
Some context:
I have a PCL for a Xamarin cross platform project, in VS 2012.
I use the Portable Microsoft HttpClient package and the Json.NET package.
I have a pretty simple WCF REST service sitting in the background.
When testing
I can access the service fine from a browser on the dev machine.
I can access it fine using a console application going via the PCL.
I can access it fine via the app, from a real android device on the WiFi network of
the same corporate network.
I can access it fine from Safari on the build Mac.
I can access it fine from Safari on the iPhone simulator on the build Mac.
The issue is, as soon as I try to access the service via the app on the iPhone simulator, I get a 407, Proxy Access Denied error.
Here is the code I'm using to set up the connection:
private static HttpRequestMessage PrepareRequestMessage(HttpMethod method, string baseUri,
string queryParameters, out HttpClient httpClient, string bodyContent)
{
var finalUri = new Uri(baseUri + queryParameters);
var handler = new HttpClientHandler();
httpClient = new HttpClient(handler);
var requestMessage = new HttpRequestMessage(method, finalUri);
if (handler.SupportsTransferEncodingChunked())
{
requestMessage.Headers.TransferEncodingChunked = true;
}
if (method == HttpMethod.Post || method == HttpMethod.Put)
{
requestMessage.Content =
new StringContent(bodyContent, Encoding.UTF8, "application/json");
}
return requestMessage;
}
That code gives me the 407 error.
I have tried setting the proxy by using various combinations of SupportsProxy and SupportsUseProxy. (Both returning false from the simulator.)
I've tried forcing the proxy settings regardless. I've tried setting the credentials on the handler itself. I've tried playing with the UseDefaultCredentials and UseProxy flags. I've also tried setting the IfModifiedSince value in the message header. I've tried using the PortableRest package as well.
All of that only seemed to make things worse. Where I was initially getting the 407 error, the call to httpClient.GetAsync would just immediately return null.
I am at a bit of a loss here, so any help would be greatly appreciated.
PS. For completeness, the rest of the surrounding code that makes the call: (please forgive crappy exception handling, I'm still playing around with the errors)
public static async Task<T> SendRESTMessage<T>(HttpMethod method, string baseUri,
string queryParameters, T contentObject)
{
HttpClient httpClient;
var payload = string.Empty;
if (contentObject != null)
{
payload = JsonConvert.SerializeObject(contentObject);
}
var requestMessage =
PrepareRequestMessage(method, baseUri, queryParameters, out httpClient, payload);
HttpResponseMessage responseMessage = null;
try
{
if (method == HttpMethod.Get)
{
responseMessage = await httpClient.GetAsync(requestMessage.RequestUri);
}
else
{
responseMessage = await httpClient.SendAsync(requestMessage);
}
}
catch (HttpRequestException exc)
{
var innerException = exc.InnerException as WebException;
if (innerException != null)
{
throw new Exception("Unable to connect to remote server.");
}
}
return await HandleResponse<T>(responseMessage);
}
private static async Task<T> HandleResponse<T>(HttpResponseMessage responseMessage)
{
if (responseMessage != null)
{
if (!responseMessage.IsSuccessStatusCode)
{
throw new Exception("Request was unsuccessful");
}
var jsonString = await responseMessage.Content.ReadAsStringAsync();
var responseObject = JsonConvert.DeserializeObject<T>(jsonString);
return responseObject;
}
return default(T);
}
This was my attempt at implementing IWebProxy quick and dirty, which I think could have made things worse:
public class MyProxy : IWebProxy
{
private System.Net.ICredentials creds;
public ICredentials Credentials
{
get
{
return creds;
}
set
{
creds = value;
}
}
public Uri GetProxy(Uri destination)
{
return new Uri("proxy addy here");
}
public bool IsBypassed(Uri host)
{
return true;
}
}
Thanks again for taking the time to read my question.

So I finally got it working.
Turns out it was something really stupid, but being new to iOS mobile dev and the fact that the service worked via Safari on the simulator threw me for a loop.
I read that the simulator uses the proxy settings as defined on the Mac. So I went to the network settings and added the service address to the proxy bypass list.
Works like a charm now.
If anybody feels there is a better way to do this, please add your opinions.

Related

"No connection could be made because the target machine actively refused it." error in Blazor project

I'm teaching myself Blazor and have run into this conundrum, where I get this error:
{"No connection could be made because the target machine actively refused it."}
The uri I call is this one:
api/employee
However, when use the full uri, such as this:
https://localhost:44376/api/employee
I get no errors at all.
Even though this is just a practice project, I'd still prefer to use a relative uri without a port number, but am not sure how to make it work.
Here's the method where I am making these calls:
public async Task<IEnumerable<Employee>> GetAllEmployees()
{
bool isEmployeeListEmpty = true; ;
IEnumerable<Employee> employeeList = null;
try
{
//string uriEmployeeList = $"https://localhost:44376/api/employee";
string uriEmployeeList = $"api/employee";
var employees = await JsonSerializer.DeserializeAsync<IEnumerable<Employee>>
(await _httpClient.GetStreamAsync(uriEmployeeList), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
if (employees != null)
{
isEmployeeListEmpty = false;
employeeList = await JsonSerializer.DeserializeAsync<IEnumerable<Employee>>
(await _httpClient.GetStreamAsync(uriEmployeeList), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
else
{
isEmployeeListEmpty = true;
}
}
catch (Exception ex)
{
Console.WriteLine("An exception occurred inside the GetAllEmployees() method of the EmployeeDataService class");
Console.WriteLine(ex.Message);
}
if (!isEmployeeListEmpty)
return employeeList;
else
return null;
}
I am doing this all on one machine with IIS Express.
UPDATE
Thank you all for your help and suggestions. It turned out that I had the ssl port defined as 44376 in the lauchSettings.json, while I had the base addresses in Startup.cs file set as https://localhost:44340/ for all three HttpClient objects I use. I changed the port in each of the base addresses to 44376 to match the 44376 port I have set up in the launchSettings.json file, and everything now works with the relative/abbreviated uri strings.
Please see if api and web project are set under "Multiple startup" and both are ACTION : "start" are not (Right click on Solution > Set Startup Projects), its seems like api project is not started and refuse the connection and getting similar error while accessing the api controller.

Application Insights: Console Application HttpClient correlation not working

I have a Console Application which I plan to use Application Insights to start telemetry. This Console App calls a Web API within it.
Operation correlation works, but the Parent hierarchy does not. Essentially, the Parent of the Web API call is not the initial call from Console Application.
Below is my code:
Console App
static async Task SendHttpOnly()
{
//Create TelemetryClient
TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault();
configuration.InstrumentationKey = "<id>";
var telemetryClient = new TelemetryClient(configuration);
RequestTelemetry requestTelemetry = new RequestTelemetry { Name = "ConsoleTest" };
var operation = telemetryClient.StartOperation(requestTelemetry);
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:37970/");
var responseTask = await client.PostAsJsonAsync<MessageDto>("MessageReceiver", new MessageDto() { Body = "Test" });
}
}
catch (Exception e)
{
operation.Telemetry.Success = false;
telemetryClient.TrackException(e);
throw;
}
finally
{
telemetryClient.StopOperation(operation);
telemetryClient.Flush();
Task.Delay(5000).Wait();
}
}
Web API
[HttpPost]
public string Post([FromBody] MessageDto dto)
{
_telemetryClient.TrackTrace($"Service Bus Message Processed: Message: {dto.Body}");
return $"Processed { dto.Body }";
}
Weird thing is, if I do a Web API to Web API call, it logs it properly. Even with the same code; the 2nd Web API call parent is the 1st Web API call.
Thankyou Water. Glad that you resolved your issue and posting the same as an answer so that it will be helpful for other community members.
Application HttpClient correlation not working because of using wrong Nuget package instead of using below package
Microsoft.ApplicationInsights.AspNetCore
We need to use the below package
Microsoft.ApplicationInsights.WorkerService
Below is the sample code for using SDK in application insights.
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.13.1" />
</ItemGroup>
For more information check the Application Insight worker service.

RestRequest Body not received in .net core web api

I am trying to build a service client to simplify calling my microservices in .net core.
Here is a service client sample:
public ProductServiceClient(SystemEnvironment.MachineEnvironment? environment = null)
{
this.url = ServiceEnvironment.Urls.GetUrl(ServiceEnvironment.Service.Product, environment);
}
private RestClient GetClient(string method)
{
return new RestClient(url + "/api/" + method);
}
private RestRequest GetRestRequest(Method method)
{
var restRequest = new RestRequest(method);
restRequest.RequestFormat = DataFormat.Json;
restRequest.AddHeader("Content-Type", "application/json");
return restRequest;
}
public FindProductsResponse FindProducts(FindProductsRequest request)
{
var restRequest = GetRestRequest(Method.GET);
restRequest.AddJsonBody(request);
var client = this.GetClient("Products");
var restResponse = client.Get(restRequest);
return new JsonDeserializer().Deserialize<FindProductsResponse>(restResponse);
}
public void Dispose()
{
}
And here is how I am trying to read it in my .net core api:
[HttpGet]
public ActionResult<FindProductsResponse> Get()
{
var request = "";
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
request = reader.ReadToEnd();
}
var buildRequest = JsonConvert.DeserializeObject<FindProductsRequest>(request);
var products = _service.FindProducts(buildRequest);
if (products != null && products.Any())
{
return new FindProductsResponse()
{
Products = products
};
}
return BadRequest("Not found");
}
However the request variable is always empty after Request.Body has been processed by the StreamReader.
If I make the same request from Postman (also using GET), I get the body just fine.
What am I doing wrong here?
EDIT: This is the unit test calling the api:
[Test]
public void Test1()
{
using (var productServiceClient = new ProductServiceClient())
{
var products = productServiceClient.FindProducts(new FindProductsRequest()
{
Id = 50
}).Products;
}
}
It can be your Request.Body has been already consumed.
Try to call Request.EnableRewind() before to open the StreamReader.
I'm not sure why you are manually doing it. It looks like you are reinventing the wheel. ASP.NET Core already does that for you.
This is what your service should look like:
[HttpGet] // oops, GET requests will not allow Bodies, this won't work
public ActionResult<FindProductsResponse> Get([FromBody]FindProductsRequest buildRequest)
{
// skip all the serialization stuff, the framework does that for you
var products = _service.FindProducts(buildRequest);
if (products != null && products.Any())
{
return new FindProductsResponse()
{
Products = products
};
}
return BadRequest("Not found");
}
And if you don't want to redo all the busy work that is retyping all the code on the client side, I suggest you read up on swagger (probably in the form of Swashbuckle). Client code can be generated. Even from within Visual Studio, if you right-click on the project and in the context menu pick "Add REST API Client...". Please don't erroneously hand-code what can be generated flawlessly by a machine instead. I don't really know what went wrong in your specific case, but searching bugs that could be avoided altogether is just busywork, that time should be spent on other parts of the program.
I just realized this is a GET request. ASP.NET will not recognize bodies for GET-Requests. You will need to make it a PUT or POST request or put your parameters in the query string.
If you happen to make that mistake as often as I did, you might want to write some unit tests that cover this. Because .NET is not helping you there. Been there, done that..

Custom InputFormatter on PostAsync exception in ASP NET Core

I have a strange problem that I don't know why is giving problems:
On client, I have this code:
HttpResponseMessage response = await _httpClient.PostAsync("http://127.0.0.1:5544/api/Blablabla", new StringContent("test"));
On server, I have implemented a custom InputFormatter that have this
public async override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
try
{
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync().ConfigureAwait(false);
return await InputFormatterResult.SuccessAsync(content).ConfigureAwait(false);
}
}
catch (Exception e)
{
return await InputFormatterResult.FailureAsync();
}
}
If I try this, the catch exception of the server is fired, giving me an exception of:
An existing connection was forcibly closed by the remote host
But.....
If in the client I make the PostAsync "sync" doing this:
HttpResponseMessage response = _httpClient.PostAsync("http://127.0.0.1:5544/api/Blablabla", new StringContent("test")).Result;
Everything works ok.
What's the problem???
Ok, I fixed it...
The problem was, as you can imagine, that the function that called postasync was async, but the one before was not, and I did not make a .Wait() to that one.
Was nothing related to asp net core, just a problem of async code from sync code.

Catching an exception from wrapped EAP request to WCF

I have a WCF request in WP8 environment that I wrapped according to this
http://msdn.microsoft.com/en-us/library/hh873178%28v=vs.110%29.aspx#EAP
My call to the WCF service proceeds as follows:
try
{
var result = await mWCFClient.PerformRequestAsync();
}
catch(Exception e)
{
}
where PerformRequestAsync is an extension method. i.e.
public static ResultType PerformRequestAsync(this WCFClient client)
{
// EAP wrapper code
}
What happens is that occasionally something goes wrong on the WCF service and it returns "NotFound". I am not 100% sure why this happens and it seems like a rare occasion. The problem, however, is not the WCF service behavior, but the fact that it breaks in the EndPerformRequestAsync() in the automatically generated WCF code instead of going to my exception handler.
How and where should I be catching this exception as it never reaches my intended handler?!
[Edit]
As per Stephen's request, I've included the wrapper code here:
public static Task<RegistrationResult> RegisterAsync(this StoreServiceReference.StoreServiceClient client, string token, bool dummy)
{
var tcs = new TaskCompletionSource<RegistrationResult>();
EventHandler<RegisterCompletedEventArgs> handler = null;
handler = (_, e) =>
{
client.RegisterCompleted -= handler;
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
client.RegisterCompleted += handler;
PerformStoreRequest(client, () => client.RegisterAsync(), token);
return tcs.Task;
}
private static void PerformStoreRequest(StoreServiceClient client, Action action, string token)
{
using (new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers[STORE_TOKEN_HTTP_HEADER] = token;
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
action.Invoke();
// TODO: Do we need to add handler here?
}
}
Now that I look at it, I think the problem stems from the nature of action invoke. But adding custom headers to WP8 WCF services already is a pain.
The action inside is an async operation, but Invoke as far as I know is not.
What's the proper way to go about it here?