I'm running through a list of both secure and unsecured domains (both http:// and https://) in an array and wish to return their status codes. How is this possible in ASP.Net Core 1.0?
so far, I have
foreach(var item in _context.URLs.ToList())
{
// Do something here with item.Domain to check for status
// For example, if item.Domain was https://example.com..
}
I tried it with regular ASP.Net syntax with this approach:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(item.Domain);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
The problem is, GetResponse doesn't work in ASP.Net Core
Can anyone help me out with an effecient solution so that the variable returned would be the status?
ex: 200, 500, 404..
EDIT - Here is my full controller AND SOLUTION:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using MyApp.Models;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;
namespace MyApp.Controllers.Api
{
public class URLsController : Controller
{
private MyAppDBContext _context;
public class newLink
{
public string Domain { get; set; }
public HttpStatusCode Status { get; set; }
}
public async Task<HttpStatusCode> GetStatusCodes(string url)
{
var client = new HttpClient();
var response = await client.GetAsync(url);
return response.StatusCode;
}
public URLsController(MyAppDBContext context)
{
_context = context;
}
[HttpPost("api/URLs")]
public async Task<IActionResult> Post(string url)
{
if (url != "")
{
// I pass a URL in through this API and add it to _context.URLs..
// I execute a status code check on the URLs after this if statement
}
List<newLink> list = new List<newLink> ();
foreach (var item in _context.URLs.ToList())
{
newLink t = new newLink();
t.Domain = item.Domain;
t.Status = await GetStatusCodes(item.Domain);
list.Add(t);
}
return Ok(list);
}
}
}
This returns an array back in this format:
[{"Domain":"https://example1.com/","Status":200},
{"Domain":"https://example2.com/","Status":200},
{"Domain":"https://example3.com/","Status":200}]
You could use HttpClient as it is easier to work with (you don't need to catch WebExceptions for the non success status codes like you would have to do with the plain HttpWebRequest and then extract the HTTP status code from the exception).
You could write a helper method that given a list of urls will return a list of corresponding status codes. This will make your code a little bit more decoupled. Do not violate the single responsibility principle. A method should not do more than 1 specific thing (in your example you were mixing some DB calls and HTTP calls into a single method which is bad practice).
public async Task<IList<HttpStatusCode>> GetStatusCodes(IList<string> urls)
{
var client = new HttpClient();
var result = new List<HttpStatusCode>();
foreach (var url in urls)
{
var response = await client.GetAsync(url);
result.Add(response.StatusCode);
}
return result;
}
Remark 1: If the url that you are trying to call is not DNS resolvable or your calling application doesn't have network access to the specified address on the target port you will not get any status code for obvious reasons. You will get a nice exception. Think about handling this case. It's up to you to decide what you want to return in the resulting collection in this case.
Remark 2: Making a GET request just for determining the HTTP status code might be a waste as you are throwing away the response body that you have already transported over the wire. If the remote resource responds to HEAD requests that might be more efficient way to determine if the server is alive. But consider this with caution as it will depend on the specifics of the web endpoint that you are calling.
Remark 3: You have undoubtedly noticed that this method is async. Well, if you intend to develop under .NET Core you'd better get accustomed to it. You could of course violate the built-in asynchronous patterns that the framework provides you by blocking the calling thread:
var urls = _context.URLs.ToList();
IList<HttpStatusCode> statusCodes = GetStatusCodes(urls).GetAwaiter().GetResult();
But this is an extremely bad practice. A more idiomatic way of working is to make all your methods asynchronous through the entire chain until you reach the main calling method which is usually provided by the framework itself and which can be asynchronous as well. For example if you are calling this inside a Web API action you could simply make it async:
[HttpGet]
[Route("api/foos")]
public async Task<IActionResult> Get()
{
var urls = _context.URLs.ToList();
IList<HttpStatusCode> statusCodes = await GetStatusCodes(urls);
return this.Ok(statusCodes);
}
Related
This question already has answers here:
Parsing Json rest api response in C# [duplicate]
(3 answers)
Closed 12 months ago.
tl;dr: I have an API that works in the browser, but I can't figure out how to return a list of items so I can traverse them in a List.
Long version:
I'm still struggling with API's and now I've hit another snag. I have the following code in my API:
[Route("api/[controller]")]
[ApiController]
public class ScheduleController : Controller
{
[HttpGet]
public IEnumerable<Schedule> GetAllSchedules()
{
using (ScheduleDataEntities entities = new ScheduleDataEntities())
{
return entities.Schedule.ToList();
}
}
[HttpGet("{id}")]
public Schedule GetIndividualSchedule(int id)
{
using (ScheduleDataEntities entities = new ScheduleDataEntities())
return entities.Schedule.FirstOrDefault(e => e.ScheduleID == id);
}
}
When I navigate to my localhost (https://localhost:7017/api/schedule) it returns the data just fine:
[{"userID":121,"weekDay":"Monday","startTime":"07:00:00","endTime":"07:15:00","createdDate":"2022-01-18T22:11:34.8966667","modifiedDate":"2022-01-18T22:11:34.8966667","active":false,"scheduleID":14414,"dayOfWeek":1,"tsType":"Normal"},
{"userID":94,"weekDay":"Wednesday","startTime":"08:45:00","endTime":"09:00:00","createdDate":"2021-11-03T13:50:50.26","modifiedDate":"2021-11-03T13:50:50.26","active":false,"scheduleID":13160,"dayOfWeek":3,"tsType":"Normal"}
...]
So far, so good. Now, I want to return the list to the client calling the API. I've made a simple test client that should get the list when I press a button:
client.Dispose();
client = new HttpClient();
client.BaseAddress = new Uri("https://localhost:7017/api/schedule/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
List<Schedule> list = GetScheduleList("https://localhost:7017/api/schedule");
//Do something with the list...
However, I can't figure out how this method should work:
static List<Schedule> GetScheduleList(string path)
{
List<Schedule> schedules = null;
HttpResponseMessage response = client.GetAsync(path);
return schedules;
}
Every tutorial I can find online, says to use GetAsync. However, that only works with the await keyword. Adding the await keyword means I have to add the async keyword to my method, which means I must return a Task<List> or a task-like type, which can't be converted to a List. If I return it as a Task, how can I then break it back down into my list of schedules?
I really feel like I've tried anything I've come across, so any help you can give is much appreciated.
try this
static async Task<List<Schedule>> GetScheduleList(string path)
{
var response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
var stringData = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<List<Schedule>>(stringData);
}
return null;
and fix the method call
List<Schedule> list = await GetScheduleList("https://localhost:7017/api/schedule");
or you can try, if you don't use async
List<Schedule> list = GetScheduleList("https://localhost:7017/api/schedule").Result;
did you try to start the web app in debug mode and find the return of the API ?
You can even use console.log to give more details;
Otherwise, I was there one day. it's CORS problem. you should add the header : Access-Control-Allow-Origin should have wildcard "*" as a value in order to be able to call https APIs on http servers.
Good afternoon colleagues, I have the following problem. I am developing a project in ASP.NET Core MVC (.NET 5) And within it I have the call to an API, the APIs return the values in JSON without problems but when I try to read from code it never goes beyond line 39 (return Json(ppodcastPortada);). In other words, it never reaches the teturn.
I am making the call from JavaScript, to render it asynchronously on the page. But the controller never returns the set of results, I really don't know why.
My Controller:
[Produces("application/json")]
public class PodcastController : Controller
{
#region "Async call API"
public async Task<JsonResult> GetPodcastLandingPortada()
{
List<PPodcast> ppodcastPortada = new List<PPodcast>();
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync("https://localhost:44379/api/Podcast/ObtenerPodcastPortadaPrincipal"))
{
string apiResponse = await response.Content.ReadAsStringAsync();
ppodcastPortada = JsonConvert.DeserializeObject<List<PPodcast>>(apiResponse);
}
}
return Json(ppodcastPortada);
}
#endregion
}
}
Hi i've been strugling to register redirect url to Kaizal webhook (its chat app from microsoft like a whatsapp), I've create asp.net API Controller to register it in my Kaizala webhook. What i want to do is whenever there is a messege or Job created on Kaizala Group, my redirect url will capture the data and save the data to my database. I think i already meet all the requirement from here https://learn.microsoft.com/en-us/kaizala/connectors/webhookvalidaton, my Get method is already returning validationToken from Header. But it always return this error when i try to register my redirect url "message": "Callback URL couldn't be validated. StatusCode = InternalServerError",.
https://kaizala007.blog/2017/12/30/exploring-kaizala-webhooks/comment-page-1/#comment-3776
From this documentation he said i need support both get and post method, already add both but my post method still doesn't do anything just return statuscode.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
namespace KaizalaTestApi.Controllers
{
public class KaizalaCallbackController : ApiController
{
// GET: KaizalaCallback
[HttpGet]
public string Get()
{
string x = Request.Headers.GetValues("validationToken").FirstOrDefault().ToString();
return x;
}
[HttpPost]
public HttpResponseMessage Post()
{
//string validationToken = Request.Headers.GetValues("validationToken").FirstOrDefault().ToString();
//string data = new StreamReader(Request.Content).ReadToEnd();
string str = Request.Content.ReadAsStringAsync().Result;
return Request.CreateResponse(HttpStatusCode.OK);
}
}
}
Why im getting that error ? do i need to do any specific thing in my post method to able make it works ?
It is not the fact that you are returning int that it worked.
The first attempt failed because of an error when invoking
Request.Headers.GetValues("validationToken").FirstOrDefault().ToString();
Most likely a null reference exception, because you tried to access the token in the header, while linked documentation states
Kaizala will generate a validation token and send a GET request to your webhook with a query parameter “validationToken”.
emphasis mine
which was avoided in the updated used of
HttpContext.Request.Query["validationToken"]
I would suggest updating the syntax to
[HttpGet]
public IActionResult Get() {
var validationToken = Request.Query["validationToken"];
return Content(validationToken);
}
Of course you can refactor to add validation code for the expected query string parameter.
I suggest the above because there is no guarantee that the token will be a valid int based on the documentation. And even if it is, this approach would be more flexible if they ever do change away from using integers as tokens.
The requirements simply states
Your service is supposed to return the validation token (received in request) in the response body as a plain-text
With that, only return exactly what was sent. Do not try to make any changes to it.
Already found how to make it works, it seem we need to return int in our get method that we get from query paramstring instead of string, i using asp net core 2.2 to make my callback url. Here take a look at my sample code to save in the database too
[HttpGet]
public int Get()
{
int validationToken = Convert.ToInt32(HttpContext.Request.Query["validationToken"]);
return validationToken;
}
[HttpPost]
public void Post([FromBody]JObject rawBody)
{
using (TheoDBContext db = new TheoDBContext())
{
var jsonData = rawBody["data"];
string name = rawBody["fromUserName"].ToString();
string title = jsonData["title"].ToString();
Kaizala newKaizala = new Kaizala();
newKaizala.Name = name;
newKaizala.Question = title;
newKaizala.Answer = "yes";
db.Kaizala.Add(newKaizala);
db.SaveChanges();
}
}
I am writing a nuget package that will consume a REST API I wrote. Im having some difficulty in calling it asynchronously using RestSharp.
I have the following controller method:
[HttpGet("{id}")]
public async Task<IActionResult> GetFeatureByIdAsync(string id)
{
if (string.IsNullOrWhiteSpace(id))
{
ModelState.AddModelError("id-Null", "The id parameter cannot be null.");
return BadRequest(ModelState);
}
var feature = await _director.GetFeatureById(id);
if (feature == null)
return NotFound();
var model = new ViewModel<Feature>(feature);
return Ok(model);
}
I have the follow class library in a seperate solution:
public async Task<bool> IsSwitchEnabledAsync(string name)
{
string fullyFormedUrl = $"{_url}/{name}";
var client = new RestClient(fullyFormedUrl) { Encoding = Encoding.UTF8 };
var request = new RestRequest(Method.GET) { RequestFormat = DataFormat.Json };
var result = await client.ExecuteTaskAsync<FeatureViewModel>(request);
var message = $"Response: {result.StatusCode}, {result.ResponseStatus}, " +
$"\n\nError: {result.ErrorException}, {result.ErrorMessage} " +
$"\n\nData: {result.Content}";
Debug.WriteLine(message);
return result.Data != null;
}
I have the following basic integration test sandbox:
[TestFixture]
public class Sandbox
{
private FeatureSwitch _sut;
[OneTimeSetUp]
public void Setup()
{
const string machineName = "localhost";
const int port = 5000;
_sut = new FeatureSwitch(machineName, port);
}
[Test]
public async Task ShouldReturnTrue()
{
var result = await _sut.IsSwitchEnabledAsync("Release_US501_AddUser");
result.Should().BeTrue();
}
}
I am looking for a little education on the best approach on how to call the API correctly? As my sandbox code is failing with an Internal Server 500 Error. This is because the api method is waiting for the nested async call to complete. So the initial request returns back to the sandbox code before the nested api call has a chance to complete.
The sandbox test code needs to wait for the API to return a result. At the moment it is not doing this.
So what is the correct approach here?
UPDATE: My issue was down to incorrect usage of a Mongo library method.
My issue came from a .chained method call on a Mongo library method:
I was trying to do the following:
Collection.Find(x => x.Name.ToLower().Equals(name.ToLower())
The code compiled but it was throwing an exception that VS studio 17 was not breaking on so i had no idea where the issue was occurring. With code lens turned on, I noticed that the failed requests highlighted in red. This opened an App Insights window which highlighted a break down of 4 InvalidOperationException() that had been thrown. That's how i discovered what the Internal Server Error 500 was about.
Anyways that's how i solved Async Web API problem - it was my first time using it on a web service so I had no idea what the expected default behaviour ought to be.
I'm developing an ASP.Net Core web application where I need to create a kind of "authentication proxy" to another (external) web service.
What I mean by authentication proxy is that I will receive requests through a specific path of my web app and will have to check the headers of those requests for an authentication token that I'll have issued earlier, and then redirect all the requests with the same request string / content to an external web API which my app will authenticate with through HTTP Basic auth.
Here's the whole process in pseudo-code
Client requests a token by making a POST to a unique URL that I sent him earlier
My app sends him a unique token in response to this POST
Client makes a GET request to a specific URL of my app, say /extapi and adds the auth-token in the HTTP header
My app gets the request, checks that the auth-token is present and valid
My app does the same request to the external web API and authenticates the request using BASIC authentication
My app receives the result from the request and sends it back to the client
Here's what I have for now. It seems to be working fine, but I'm wondering if it's really the way this should be done or if there isn't a more elegant or better solution to this? Could that solution create issues in the long run for scaling the application?
[HttpGet]
public async Task GetStatement()
{
//TODO check for token presence and reject if issue
var queryString = Request.QueryString;
var response = await _httpClient.GetAsync(queryString.Value);
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
[HttpPost]
public async Task PostStatement()
{
using (var streamContent = new StreamContent(Request.Body))
{
//TODO check for token presence and reject if issue
var response = await _httpClient.PostAsync(string.Empty, streamContent);
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType?.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
}
_httpClient being a HttpClient class instantiated somewhere else and being a singleton and with a BaseAddressof http://someexternalapp.com/api/
Also, is there a simpler approach for the token creation / token check than doing it manually?
If anyone is interested, I took the Microsoft.AspNetCore.Proxy code and made it a little better with middleware.
Check it out here: https://github.com/twitchax/AspNetCore.Proxy. NuGet here: https://www.nuget.org/packages/AspNetCore.Proxy/. Microsoft archived the other one mentioned in this post, and I plan on responding to any issues on this project.
Basically, it makes reverse proxying another web server a lot easier by allowing you to use attributes on methods that take a route with args and compute the proxied address.
[ProxyRoute("api/searchgoogle/{query}")]
public static Task<string> SearchGoogleProxy(string query)
{
// Get the proxied address.
return Task.FromResult($"https://www.google.com/search?q={query}");
}
I ended up implementing a proxy middleware inspired by a project in Asp.Net's GitHub.
It basically implements a middleware that reads the request received, creates a copy from it and sends it back to a configured service, reads the response from the service and sends it back to the caller.
This post talks about writing a simple HTTP proxy logic in C# or ASP.NET Core. And allowing your project to proxy the request to any other URL. It is not about deploying a proxy server for your ASP.NET Core project.
Add the following code anywhere of your project.
public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri)
{
var request = context.Request;
var requestMessage = new HttpRequestMessage();
var requestMethod = request.Method;
if (!HttpMethods.IsGet(requestMethod) &&
!HttpMethods.IsHead(requestMethod) &&
!HttpMethods.IsDelete(requestMethod) &&
!HttpMethods.IsTrace(requestMethod))
{
var streamContent = new StreamContent(request.Body);
requestMessage.Content = streamContent;
}
// Copy the request headers
foreach (var header in request.Headers)
{
if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
requestMessage.Headers.Host = uri.Authority;
requestMessage.RequestUri = uri;
requestMessage.Method = new HttpMethod(request.Method);
return requestMessage;
}
This method covert user sends HttpContext.Request to a reusable HttpRequestMessage. So you can send this message to the target server.
After your target server response, you need to copy the responded HttpResponseMessage to the HttpContext.Response so the user's browser just gets it.
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
{
if (responseMessage == null)
{
throw new ArgumentNullException(nameof(responseMessage));
}
var response = context.Response;
response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
foreach (var header in responseMessage.Content.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
response.Headers.Remove("transfer-encoding");
using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(response.Body, _streamCopyBufferSize, context.RequestAborted);
}
}
And now the preparation is complete. Back to our controller:
private readonly HttpClient _client;
public YourController()
{
_client = new HttpClient(new HttpClientHandler()
{
AllowAutoRedirect = false
});
}
public async Task<IActionResult> Rewrite()
{
var request = HttpContext.CreateProxyHttpRequest(new Uri("https://www.google.com"));
var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, HttpContext.RequestAborted);
await HttpContext.CopyProxyHttpResponse(response);
return new EmptyResult();
}
And try to access it. It will be proxied to google.com
A nice reverse proxy middleware implementation can also be found here: https://auth0.com/blog/building-a-reverse-proxy-in-dot-net-core/
Note that I replaced this line here
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
with
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToString());
Original headers (e.g. like an authorization header with a bearer token) would not be added without my modification in my case.
I had luck using twitchax's AspNetCore.Proxy NuGet package, but could not get it to work using the ProxyRoute method shown in twitchax's answer. (Could have easily been a mistake on my end.)
Instead I defined the mapping in Statup.cs Configure() method similar to the code below.
app.UseProxy("api/someexternalapp-proxy/{arg1}", async (args) =>
{
string url = "https://someexternalapp.com/" + args["arg1"];
return await Task.FromResult<string>(url);
});
Piggy-backing on James Lawruk's answer https://stackoverflow.com/a/54149906/6596451 to get the twitchax Proxy attribute to work, I was also getting a 404 error until I specified the full route in the ProxyRoute attribute. I had my static route in a separate controller and the relative path from Controller's route was not working.
This worked:
public class ProxyController : Controller
{
[ProxyRoute("api/Proxy/{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
This does not:
[Route("api/[controller]")]
public class ProxyController : Controller
{
[ProxyRoute("{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
Hope this helps someone!
Twitchax's answer seems to be the best solution at the moment. In researching this, I found that Microsoft is developing a more robust solution that fits the exact problem the OP was trying to solve.
Repo: https://github.com/microsoft/reverse-proxy
Article for Preview 1 (they actually just released prev 2): https://devblogs.microsoft.com/dotnet/introducing-yarp-preview-1/
From the Article...
YARP is a project to create a reverse proxy server. It started when we noticed a pattern of questions from internal teams at Microsoft who were either building a reverse proxy for their service or had been asking about APIs and technology for building one, so we decided to get them all together to work on a common solution, which has become YARP.
YARP is a reverse proxy toolkit for building fast proxy servers in .NET using the infrastructure from ASP.NET and .NET. The key differentiator for YARP is that it is being designed to be easily customized and tweaked to match the specific needs of each deployment scenario. YARP plugs into the ASP.NET pipeline for handling incoming requests, and then has its own sub-pipeline for performing the steps to proxy the requests to backend servers. Customers can add additional modules, or replace stock modules as needed.
...
YARP works with either .NET Core 3.1 or .NET 5 preview 4 (or later). Download the preview 4 (or greater) of .NET 5 SDK from https://dotnet.microsoft.com/download/dotnet/5.0
More specifically, one of their sample apps implements authentication (as for the OP's original intent)
https://github.com/microsoft/reverse-proxy/blob/master/samples/ReverseProxy.Auth.Sample/Startup.cs
Here is a basic implementation of Proxy library for ASP.NET Core:
This does not implement the authorization but could be useful to someone looking for a simple reverse proxy with ASP.NET Core. We only use this for development stages.
using System;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
namespace Sample.Proxy
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(options =>
{
options.AddDebug();
options.AddConsole(console =>
{
console.IncludeScopes = true;
});
});
services.AddProxy(options =>
{
options.MessageHandler = new HttpClientHandler
{
AllowAutoRedirect = false,
UseCookies = true
};
options.PrepareRequest = (originalRequest, message) =>
{
var host = GetHeaderValue(originalRequest, "X-Forwarded-Host") ?? originalRequest.Host.Host;
var port = GetHeaderValue(originalRequest, "X-Forwarded-Port") ?? originalRequest.Host.Port.Value.ToString(CultureInfo.InvariantCulture);
var prefix = GetHeaderValue(originalRequest, "X-Forwarded-Prefix") ?? originalRequest.PathBase;
message.Headers.Add("X-Forwarded-Host", host);
if (!string.IsNullOrWhiteSpace(port)) message.Headers.Add("X-Forwarded-Port", port);
if (!string.IsNullOrWhiteSpace(prefix)) message.Headers.Add("X-Forwarded-Prefix", prefix);
return Task.FromResult(0);
};
});
}
private static string GetHeaderValue(HttpRequest request, string headerName)
{
return request.Headers.TryGetValue(headerName, out StringValues list) ? list.FirstOrDefault() : null;
}
public void Configure(IApplicationBuilder app)
{
app.UseWebSockets()
.Map("/api", api => api.RunProxy(new Uri("http://localhost:8833")))
.Map("/image", api => api.RunProxy(new Uri("http://localhost:8844")))
.Map("/admin", api => api.RunProxy(new Uri("http://localhost:8822")))
.RunProxy(new Uri("http://localhost:8811"));
}
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}