Cannot Consume ASP.NET REST API Deployed Locally - c#

I have made a very simple Web API in ASP.NET and deployed it locally with IIS, but I cannot seem to use it. I've tried using it with HTTPClient in Xamarin, as well as in Java, but something in the ASP.NET project is not allowing me to access it. I am not sure if the problem is because it's deployed locally, though. Here are the errors I receive in Java and .NET:
Java:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
.NET:
at System.Net.Http.HttpClientHandler+<SendAsync>d__64.MoveNext () [0x00478] in <996a681f30a44cd685a4da54e11956e2>:0
Calling Method:
public async Task<List<School>> GetSchools()
{
try
{
var response = await client.GetAsync("schools");
string responseJson = await response.Content.ReadAsStringAsync();
List<School> schools = JsonConvert.DeserializeObject<List<School>>(responseJson);
return schools;
}
catch (HttpRequestException e)
{
return null;
}
}

The issue was caused by the program using an SSL Certificate. To fix, I just went into the projects properties and unchecked the setting 'Enable SSL'.

Related

WPF App exits without response or exception at HttpClient PostAsync method

I have gone through several SO and forums - spending over several hours attempting the several answers/comments I found on these sites. I still haven't been able to resolve the issue.
Note 1: It worked on my laptop before - all further developments were made on a separate branch. Neither the original branch nor the new branch works. It works on my team mate's laptop and we still haven't been able to figure out the issue.
Note 2: I have tried re-cloning the original branch in a separate directory and that fails too. Again, we couldnt reproduce the issue on my team mate's system.
Environment - Windows 10, Visual Studio 2019, WPF App (.NET Framework 4.8), C# 8
public class SomeClient
{
private readonly string _host;
private readonly HttpClient _client;
public SomeClient(HttpClient client, string host)
{
_host = host;
_client = client;
}
public async Task<string> GetResponse(string request)
{
HttpContent content = new StringContent(request, Encoding.UTF8, "application/xml");
HttpResponseMessage body = await _client.PostAsync(_host, content);
return await body.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
Calling Code (Test Method)
[TestClass]
public class SomeClientShould
{
[TestMethod]
public async Task ReturnResponse()
{
string request = "";
SomeClient client = new SomeClient(new HttpClient(), #"http:\\localhost:9888\");
string response = await client.GetResponse(request);
Assert.AreEqual("<RESPONSE>Server is Running</RESPONSE>", response);
}
}
Here I am not making any request, sending an empty string which should respond with the string shown in the Assert (passes on my team mate's system, Postman on my system works also).
I have tried various combo's of ConfigureAwait(false), also there is no blocking code - its async all the way. Even a simple test method shown above exits after the PostAsync line without executing the next line. Try-Catch is not catching any exception and Im having a breakdown.
So dummy me, first of all made a mistake with the host uri - the slashes had to be the other way round in the test project - "http://localhost:9888/". So the tests run now.
Next issue, between my projects I had a version mismatch of the Microsoft.Bcl.AsyncInterfaces library.
Somehow one project had the latest version referenced but the other didn't? Perhaps the issue came about during merging of the original branch - before my teammate and I created our respective dev branches for further development. Anyway it works now.

Microsoft Translator API work using console but not working within MVC

I have been able to get the Microsoft Translator API to work with creating a console project. I could only find examples with using console projects.
When trying to get the Translator API working within a controller I am not having any luck. I am using the same code.
Do I need to add some other type of reference to get the Translator to work with in MVC?
public async Task<string> GetAuthenticationToken(string key)
{
string endpoint = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "xxxxxxxxxxxxxxx501b7b1ce");
var response = await client.PostAsync(endpoint, null);
var token = await response.Content.ReadAsStringAsync();
return token;
}
}
Error Message
Is there any particular reason you have to create the console application first and then run it as such?
Instead of running the executable from your MVC project, I would recommend calling the TranslatorAsync() function instead.
My guess would be that the process.Start() and process.Close() calls are killing the process before it has a chance to do anything. However, without more specifics on how the function is failing, it's hard to give a better answer.
I had to change
TranslateAsync(productTest, getUserName).Wait;
to
await TranslateAsync(productTest, getUserName);
It’s working now.

Detect cause of timeout in Azure Web App

I am writing an bot in C# with the Microsoft Bot Framework which is hosted as Azure web app and calls either some Azure API or a Google Cloud API.
Locally everything works fine but when deployed to Azure the Call to the Google Cloud API never returns and my the Microsoft Bot Frameworks gives me an timeout error message.
I searched through the Azure portal in order to find some more detailed information why this outgoing call might not return correctly but so far I found nothing useful. I can't see any error on the diagnostics sites and remote debugging just never return from the API calls.
Does anybody know if I can enable some more debug/error information for this problem?
Edit after comments:
#Mark C.: I am able to call and get a result form the Google Service (text sentiment) when I run the app locally, so the Google Cloud API should be fine.
#Hackerman: The mapping is know to me. I try to compare some Services between Azure and Google, in this case the text sentiment API. I enabled stream logging, but there are no errors/warnings printed out.
#Bruce MSFT: The method is like this. Both azure and google paths work locally. Only the Azure path works when deployed to Azure web apps. When I remote debug the Azure Web App I can step to "client.AnalyzeSentimentAsync" and when I press next the next line is never reached. Instead after 10 (?) minutes I get an exception from mscorlib: "{"Status(StatusCode=DeadlineExceeded, Detail=\"Deadline Exceeded\")"}"
public async Task<int> DetectSentiment(string text, bool useAzure = false)
{
if (useAzure)
{
var request = new SentimentRequest();
request.Documents.Add(new AzureDocument
{
Id = Guid.NewGuid().ToString(),
Text = text
});
var client = new SentimentClient(_key);
var response = await client.GetSentimentAsync(request);
return Convert.ToInt32(response.Documents[0].Score * 100);
}
else
{
try
{
var client = LanguageServiceClient.Create();
var response = await client.AnalyzeSentimentAsync(new GoogleDocument
{
Content = text,
Type = GoogleDocument.Types.Type.PlainText
});
return Convert.ToInt32((response.DocumentSentiment.Score + 1) * 50);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}

Azure mobile app return 401 (Unauthorized) even after successful login.

I'm using custom authentication with facebook to let my users login to the app service. Unfortunately I'm getting the following error when calling "InvokeApiAsync"
"Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: The request could not be completed. (Unauthorized)"
I'm using the following code that worked with the 1.x.x branch of the NuGet package, Its only after updating that I get this error message.
Newtonsoft.Json.Linq.JObject jToken = new Newtonsoft.Json.Linq.JObject();
jToken.Add("access_token", token);
var user = await _mobileService.LoginAsync(MobileServiceAuthenticationProvider.Facebook, jToken);
var result= await _mobileService.InvokeApiAsync<GetContactListRequest, GetContactListResponse>("GetContactList", new GetContactListRequest());
The LoginAsync part works and the user variable contains an user with a token (_mobileService.CurrentUser does as well). It's when I call "InvokeApiAsync that i get the Unauthorized error.
The mobile service
[Authorize]
public class GetContactListController : ApiController
{
// POST api/CustomRegistration
public HttpResponseMessage Post(GetContactListRequest request)
{
try
{
return this.Request.CreateResponse(HttpStatusCode.OK, new GetContactListResponse());
}
catch (Exception ex)
{
return this.Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
}
}
}
Any pointers?
Try enabling application logging for your mobile app backend (you can do this in the portal). If the issue is in the platform authentication pipeline, then you will get more details about the auth failure there. Otherwise, it's more likely to be in your application code (either client or server).
If you have a Fiddler trace, that would also be helpful in diagnosing the problem.

Upload files to Azure Blob storage through WebApi without accessing local filesystem

I'm trying to upload files from local command line client to Azure storage through web-api.
I'm using Azure Web-Site for that. Working with the client is not a problem. And I've got everything working locally fine. Here is the web-api code:
public async Task<HttpResponseMessage> PostUpload()
{
// need a local resource to store uploaded files temporarily
LocalResource localResource = null;
try
{
// Azure web-site fails here
localResource = RoleEnvironment.GetLocalResource("TempStorage");
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Unable to get access to local resources");
}
var provider = new MultipartFormDataStreamProvider(localResource.RootPath);
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
// snipped validation code
var container = // code to get container
foreach (var fileData in provider.FileData)
{
var filename = GetBlobName(fileData);
var blob = container.GetBlockBlobReference(filename);
using (var filestream = File.OpenRead(fileData.LocalFileName))
{
blob.UploadFromStream(filestream);
}
File.Delete(fileData.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
Everything works fine when I run locally, but as soon as I deploy web-site in Azure, I can't upload, because Azure Web-Sites don't have access to LocalResource. And I'll need to switch to Azure Web-Role. I can switch, but accessing local file system is bothering me all together.
And LocalResource is required for instance of MultipartFormDataStreamProvider(). And I have not found alternative ways to upload files to WebApi. My plan was to channel through upload directly to Azure, without storing anything on a local HDD.
Is there any other way to upload files?
p.s. I have seen usages of Shared Access Signatures where I can give client application a url with signature and let the client upload directly to Azure Blog. But I'm not sure about how secure that is going to be and not really comfortable (yet) with passing the signatures down to the client. At the moment I presume the client is going to be run in very hostile environment and nothing can be trusted coming back from the client.
UPD My final solution involved using write only Shared Access Signature issued on the server and passed down to the client. And client then uploads files directly to Azure. This way I save a lot of hassle with managing uploaded files. And here is more detailed description of my solution.
This isn't exactly the answer you are looking for, but you can use local storage with Azure Websites using MultiPartFileStreamProvider and Path.GetTempPath(). The code would look something like this
public async Task<HttpResponseMessage> PostUpload()
{
var provider = new MultipartFileStreamProvider(Path.GetTempPath());
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
// do the rest the same
}
I found this StackOverflow article that overrides the MultipartFormDataStreamProvider so that Files are not stored locally first, but directly written to an AWSStream. See:
Is it possible to override MultipartFormDataStreamProvider so that is doesn't save uploads to the file system?
But I have to say I also like the solution of trailmax.
One possible solution to get your code to work as is with a LocalResource would be to host this inside of a worker process that self-hosts web api via Owin.
You can find a simple walkthrough at: http://www.asp.net/web-api/overview/hosting-aspnet-web-api/host-aspnet-web-api-in-an-azure-worker-role
You just need to startup the Owin-hosted api within the OnStart() method of the RoleEntryPoint. Keep in mind you can also return Html from a web api response so you can make a worker role a very flexible base project.
Here's a quick snippet showing how to set up the Owin host from the link above:
private IDisposable _webApp = null;
public override bool OnStart() {
ServicePointManager.DefaultConnectionLimit = 5;
var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["DefaultEndpoint"];
var baseUri = string.Format("{0}://{1}", endpoint.Protocol, endpoint.IPEndpoint);
_webApp = WebApp.Start<Startup>(new StartOptions(baseUri));
return base.OnStart();
}
public override void OnStop() {
if (_webApp != null) {
_webApp.Dispose();
}
base.OnStop();
}
...
using System.Web.Http;
using Owin;
class Startup {
public void Configuration(IAppBuilder app) {
var config = new HttpConfiguration();
config.Routes.MapHttpRoutes("Default", "{controller}/{id}",
new { id = RouteParameter.Optional });
app.UseWebApi(config);
}
}

Categories

Resources