Call internal Web Api from a external server - c#

I built a Web Api that is hosted in a server that just allow internal access and i have a Cliente-Side aplication. I have to build something in the middle to make this connection.
Cliente-Side <-> SOMETHING <-> Web Api (internal access) -> DataBase
What i need to build ? I am a begginer and i have this problem now.

Make sure you can hit the URL of your web api from your device. Easy route is to run the network capabilities sample here on your device and see you can hit the server using the IsReachable and IsRemoteReachable APIs. Its Xamarin Forms, not pure Xamarin, but should let you see if you can hit your server.
https://blogs.msdn.microsoft.com/devfish/2016/06/22/xam-plugins-connectivity-all-apis-sample/

Here is an implementation of a function which show get and post data from the client app to web service, this will work on desktop app(win form etc). To access the web api from another web site using the same below code you have to enable cors in the web api project
public static async Task UploadAsync(ReadingModel reading)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://your-api-domain.net/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
HttpResponseMessage response = await client.GetAsync("api/yourapi");
if (response.IsSuccessStatusCode)
{
Product product = await response.Content.ReadAsAsync<Product>();
Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
}
// HTTP POST
try
{
HttpResponseMessage response = await client.PostAsJsonAsync("api/yourapi", reading);
if (response.IsSuccessStatusCode)
{
// do your stuff
}
}
catch (Exception)
{
}
}
}

Related

SecurityTokenInvalidSignatureException when authorizing from Xamarin.ios using MSAL

I have a .NET Core Web Application and Web Api that I am calling from an IOS app (using Xamarin.ios). The web application is hosted in IIS on a private server. I am using MSAL single tenant to authenticate. That part seems to be working fine, as I can log in and get an access token.
The browser works fine, I can navigate to the WebApi no problem. However, when I try to make an http request to my Api, I get a 401 in my app. Here's the call:
string accessToken = await SecureStorage.GetAsync("AccessToken");
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//_httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
HttpResponseMessage response = await _httpClient.GetAsync($"api/{uriSuffix}");
response.EnsureSuccessStatusCode();
string reply = await response.Content.ReadAsStringAsync();
return reply;
Debugging the server, I'm getting:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: 'IDX10511: Signature validation failed.
In the PII of the exception, it has my email, name, etc, leading me to believe that it successfully got my info from the token.
Any ideas?
I finally figured out the issue (or at least got it working). It had to do with the Audience. What is the Audience, you say? I couldn't tell you. But mine wasn't working because it's SINGLE-TENANT. Most tutorials I read used multi-tentant, which is handled differently.
Here's the change:
private IPublicClientApplication _pca;
readonly string[] Scopes =
{
"<tenant_id>/<api_permission>"
};
public AuthenticationHelper()
{
_pca = PublicClientApplicationBuilder.Create(<tenant_id>)
.WithIosKeychainSecurityGroup("com.microsoft.adalcache")
.WithRedirectUri("msauth.<bundle_id>://auth")
.WithAuthority("https://login.microsoftonline.com/<client_id>/v2.0")
.Build();
}
The important bit is the "Scopes" variable. Note, I prefix the api permission with "tenant_id\", where tenant_id is the guid of my tenant. Once I added that, it worked.

Using Azure Hybrid Connection to connect to internal Web API

Very new to Azure, and I have an internal web API on an internal address http://internal-server:182/api/policies. I have set up a Hybrid Connection internal-service.servicebus.windows.net. This is connected and working.
My struggle is getting the C# code working to connect and retrieve the data. After a number of days, I have reviewed various articles, videos etc and all seem more advanced than what I am trying to do, which is just call the Web API and read the JSON. I have tried to simplify the code but receive the error:
401 MalformedToken: Invalid authorization header: The request is missing WRAP authorization credentials.
At present I have the followed code:
using (var client = new HttpClient())
{
var url = "http://internal-service.servicebus.windows.net";
var tp = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", "<key goes here>");
var token = tp.GetWebTokenAsync(url, string.Empty, true, TimeSpan.FromHours(1))
.GetAwaiter()
.GetResult();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ServiceBusAuthorization", token);
var response = client.GetAsync("/api/policies").Result;
string res = "";
using (HttpContent content = response.Content)
{
// ... Read the string.
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
Label1.Text = res;
}
}
Any help or direction would be much appreciated? Once this code is working the Web App will be published as an Azure Web App.
Seems that your are not sending the right header.
First suggestion: intercept the call with a proxy like fiddler, to do that add a proxy config to your call to localhost port 8888, after this you can try some request and see the raw http you are sending to the server, you can also modify it until it works, once you have this modify your code until it send the same raw http.
You can find more info about this here:
Microsoft Azure CreateQueue using Simple REST Client
https://github.com/ytechie/event-hubs-sas-generator

Consume REST service in MVC 6

I need help. I am creating an MVC 6 application and stuck on the part where I should consume JSON from a REST service. I could not find the way I should connect my project to the service and then consume it.
There is no way to add service reference as in previous versions and I could not find it ASP.NET 5 documentation where the policy for using 3rd party services in MVC 6 is regulated. Did someone had the same issue?
To get the JSON from RESTful service in MVC you just make a http call to the service API and parse the response with model that contains the properties of the json. You can read more about that here:
http://bitoftech.net/2014/11/18/getting-started-asp-net-5-mvc-6-web-api-entity-framework-7/
An example would look like something like this:
public YourModel MakeRequest(string requestUrl)
{
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception(String.Format("Server error (HTTP {0}: {1}).", response.StatusCode, response.StatusDescription));
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
var responseObject = serializer.Deserialize<YourModel>(response);
return responseObject;
}
}
catch (Exception e)
{
// catch exception and log it
return null;
}
}
There is no "add a service reference" feature for REST services in ASP.NET (like it is for WSDL described ones).
There never was. You consume the service as you would consume it directly from your browser using javascript.
The difference is that you need to write similar code in .NET using any http client (HttpClient or RestSharp are the most popular).
There are some efforts to make the REST services easier to consume. Swagger is the tool I use to describe my API. It also allows to generate client code for various languages.

Calling a Web api from another Web api

Is it somehow possible to make a Web api that calls another web api?
I am using the code below to access a web api from my web api, but it never return from the call. If I use the code from a console app, it is working fine.
public void DoStuff(){
RunAsync().Wait();
}
public static async Task RunAsync(){
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:53452/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
HttpResponseMessage response = await client.GetAsync("umbraco/api/Member/Get?username=test");
if (response.IsSuccessStatusCode)
{
string user = await response.Content.ReadAsAsync<string>();
}
}
I also went through the same problem, after much research I discovered that the await operator does not stop the work if the HttpClient returns error 500. To work around the problem I used Task.Wait().
var response = client.GetAsync ("umbraco/api/Member/Get?username=test");
response.Wait ();
I hope this helps others.
Yes you can make a call to a remote web api within the action method of a web api controller.
Lets eliminate the obvious first.
If you set a breakpoint at the start of this action method it is getting hit right? If not then the issue lies in the routing not the action method.
If you set a breakpoint at the if statement does it get hit or is the client.GetAsync() call never returning?
If you haven't done already you may wish to use a tool like fiddler (http://www.telerik.com/fiddler) to compare the request & response from a working use of the api and this broken one. I know you said it is identical to a working implementation but I have found fiddler invaluable to verify exactly what is being sent "on the wire".

What's the right approach for Integration Testing an api built on ASP.NET MVC?

I'm building an api that uses OAuth2. I've successfully unit tested all of the individual pieces but now I need to do some integration testing. Basically I want to be able to inspect the http responses from the server to make sure everything is in working order. Ideally I'd like to be able to spin up the web developement server in Visual Studio to host the site in and then make a bunch of requests to it and inspect the results.
What's the best approach to doing this and what tools should I be using?
I would recommend you deploying your application on a staging server (maybe even as a part of the build process so that this would be a single button click action) and then firing the HTTP client requests against this server, the way a real .NET client is supposed to use your API.
Create a Continuous Integration Server
install TeamCity
install Ruby
install Albacore
Have a rake script do the following
1. check out files from source control
2. build locally
3. deploy api to local iis
4. run integration tests against localhost api
This started to sound familiar. See here
Here is an example from my API integration tests. Let me know if you want more details.
I am using mspec.
I run it aganst localhost, our staging server, and our production server (a limited set of tests) to make sure all http connections are working.
public class _GET_no_criteria : specs_for_endpoint_test
{
Establish context = () =>
{
Uri = C.Endpoint;
Querystring = "";
ExecuteJsonGetRequest();
SetValidId();
};
It should_have_status_code_200_ok =()=>
IsHttp_200OK();
It should_have_categories = () =>
{
responseText.ShouldNotBeEmpty();
PutsAll(responseText);
};
}
From the base class
public static void ExecuteGetRequest(string contentType)
{
httpcontext = HttpContext.Current;
request = (HttpWebRequest)WebRequest.Create(BaseUri + Uri + Querystring);
request.Method = C.HTTP_GET;
request.ContentType = contentType;
request.Headers[C.AUTHORIZATION] = token;
// GetResponse reaises an exception on http status code 400
// We can pull response out of the exception and continue on our way
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
response = (HttpWebResponse) ex.Response;
}
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
reader.Close();
}
}
public static void ExecuteJsonGetRequest()
{
ExecuteGetRequest(C.CONTENT_JSON);
}

Categories

Resources