I have 2 Web Apps in .Net Core, the first is called 'MiddelwareApp' that is public To the internet and Receive Requests from clients in encrypted Case Then Decrypt them and sends Requests to the second App called "MainApp" located at another server.
'MainApp' contains My Controllers In addition to Static Files in WWWRoot.
Sending Requests from MiddlewareApp , mapping to controllers in MainApp, and getting the correct data are done without any problem. But the problem with Static Files
What I want is to access my static files in MainApp from Middlewareapp in Another server.
Currently, I am in the local host MainApp in port 7000 and middleware in port 7001
In program File of mainApp:
.........
app.UseHttpsRedirection();
//to allow access files in wwwroot without any server-side processing.
app.UseStaticFiles(new PathString("/app-Assets"));
// to allow access files not in wwwroot
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"Assets")),
RequestPath = new PathString("/app-Assets")
});
app.UseRouting();
......
I tried In the program file of Middleware app :
...
app.UseFileServer(
new FileServerOptions
{
FileProvider = new PhysicalFileProvider(#"\\https:\\localhost:7000\app-Assets"),
// this is url of static file in Main app
RequestPath = new PathString("/app-Assets"),
EnableDirectoryBrowsing = false
});
...
in my HTML I want to access Image directly from URL of middleware port 7001
<img src="https://localhost:7001/app-Assets/myImage.jpg"\>
I expected that image src would send request To middleware then 'UseFileServer' in its program
access static file of Main app on another server
The error say
System.IO.DirectoryNotFoundException: '//https://localhost:7000/app-Assets/'
but if i make path '{LocalDrive}/app-Assets/' it work
I Follow some guidelines for that but now work for me because
https://www.jauernig-it.de/asp-net-coreiis-serving-content-from-a-file-share/
How to use static content in .NET Core from server location?
if some one need some additional details ,I will do
Thanks for your helping
Edit: The solution Worked For me
Using app.UseFileServer() method in Middleware App not Work at All ,So I tried another way that make the same effect
[Route("GetImage")]
[HttpGet]
public async Task<IActionResult> Get(string filePath, bool inline = true)
{
if (string.IsNullOrWhiteSpace(filePath))
throw new ArgumentNullException(nameof(filePath));
filePath = Path.Combine("app-Assets\\", filePath);
var httpClient = _httpClientFactory.CreateClient("AnotherServerDirectory");
var response = await httpClient.GetAsync(filePath);
var ms = new MemoryStream(await response.Content.ReadAsByteArrayAsync());
var ext = Path.GetExtension(filePath).ToLowerInvariant();
var cd = new ContentDisposition
{
Inline = inline // false = prompt the user for downloading; true = browser to try to show the file inline
};
Response.Headers.Add("Content-Disposition", cd.ToString());
return new FileStreamResult(ms, GetMimeTypes()[ext]);
}
I set 'Content-Disposition' to control if I want to download the image or display it directly from <img src=""> tag
then in Html I make
<img src="https://localhost:700/GetImage?filePath=myImage.jpg"\>
If you only want the result, then you can use server to return to the client.
Example:
<img src="https://localhost:7001/app-Assets?image=myImage.jpg"\>
Stream image from controller's
[HttpGet]
[Route("app-Assets")]
public IActionResult AssetsImage(string image)
{
var image = System.IO.File.OpenRead($"app-Assets/{image}");
return File(image, "image/jpeg");
}
I'm trying to integrate Twilio with my ASP.NET Core MVC Application but in the controller, I'm getting an error in my return statement.
**Cannot implicitly convert type 'System.Web.Mvc.ContentResult' to 'Microsoft.AspNetCore.Mvc.ContentResult'
**
Controller Code
using Microsoft.AspNetCore.Mvc;
using System.Configuration;
using Twilio;
using Twilio.AspNet.Mvc;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using Twilio.TwiML;
namespace TwilioTesting.Controllers
{
public class SMSController : TwilioController
{
public ContentResult Index()
{
var accountSid = "AC12345678";
var authToken = "12345678";
TwilioClient.Init(accountSid, authToken);
var to = new PhoneNumber("+92313887998");
var from = new PhoneNumber("+19898980625");
var message = MessageResource.Create(
to: to,
from: from,
body: "Message from Kamran");
return Content(message.Sid);
}
}
}
You have a using Twilio.AspNet.Mvc; import which is not for .NET Core & is for ASP.NET MVC. It is unexpectedly importing in System.Web.Mvc.ContentResult which is conflicting with the import of Microsoft.AspNetCore.Mvc.ContentResult.
Remove it and replace it with using Twilio;.
I'm currently implementing an Azure Function App that exposes a few Functions (mostly gets).
The following code seems to have an issue:
using System;
using System.Collections.Specialized;
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using InternalVacanciesAzureFunction.Model;
using Microsoft.Extensions.Options;
using System.Text.Json;
using System.Collections.Generic;
namespace IVAFunction
{
public class PostFunction
{
private readonly HttpClient _httpClient;
public PostFunction(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient();
}
[Function("postFunction")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", "put")] HttpRequestData req,
FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger("PostFunction");
logger.LogError("Code hit: PostFunction.cs");
HttpResponseData response = req.CreateResponse();
string body = new System.IO.StreamReader(req.Body).ReadToEnd();
JsonResponse data = Nfunction.postFunction(_httpClient, "/PostFunction", body, logger, requestPrincipalName);
if (data.responseType.Equals(ResponseType.OK))
{
response.StatusCode = HttpStatusCode.OK;
}
else
{
response.StatusCode = HttpStatusCode.InternalServerError;
}
response.Headers.Add("Content-Type", "application/json; charset=utf-8");
response.WriteString(data.json);
return response;
}
}
}
The data that is posted to this function is a JSON including a BASE64 encoded string in two of the fields. The max size for each of those two fields is 1.5MB. Everytime I post something small e.g. 2 x 400B, everything goes fine. But when I sent something like 2 x 900kB the logging show up like this:
2021-12-07T07:42:28.455 [Debug] Request successfully matched the route with name 'postFunction' and template 'api/postFunction'
2021-12-07T07:42:29.129 [Information] Executing 'Functions.postFunction' (Reason='This function was programmatically called via the host APIs.', Id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
The "Code hit" logger code is never hit and after a while the function times out.
Anyone having a clue what is going on? I can reproduce the issue on both my local dev environment as well on actual Azure.
You got a lot of missing directives or assembly references there
except for that the last } is unnenecessary.
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();
}
}
}
I'm developping a webapplication. For the security of the users information i need a https connection. I'm developping this local at the moment. I have followed the tutorial on: http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx
When I build my project the page loads but the url is: http://...
In my code i have placed:
[RequiresSSL]
public ActionResult Index()
{
//var model = Adapter.EuserRepository.GetAll();
return View(db.Eusers.ToList());
}
code from site:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace extranet.Helpers
{
public class RequiresSSL: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequestBase req = filterContext.HttpContext.Request;
HttpResponseBase res = filterContext.HttpContext.Response;
//Check if we're secure or not and if we're on the local box
if (!req.IsSecureConnection && !req.IsLocal)
{
var builder = new UriBuilder(req.Url)
{
Scheme = Uri.UriSchemeHttps,
Port = 443
};
res.Redirect(builder.Uri.ToString());
}
base.OnActionExecuting(filterContext);
}
}
}
What am i missing that the url isn't https based? Is this because I'm working local?
Thanks in advance
Your filter checks to see if the request is local with this statement: && !req.IsLocal. If it is, then it doesn't redirect. If you remove that statement then you'll be required to access the action via HTTPS regardless if you're local or not.
when i remove that piece of code then i get a 401 - can't make
connection with the server localhost, but the link is https now
Removing that part of the code is only part of the solution to your problem. Going back to your original question of "how you can use https" then you need to enable it using this guide.