Get remote IP address in DotVVM - c#

I'm building an app using DotVVM framework (ver 1.1.9) using AspNet.Core and .NET Framework 4.7.1.
At some point I need to log remote user's IP address. Is there a way to get it inside the ViewModel? I've seen many tutorials
There is a property Context in ViewModelBase that has property HttpContext but it's some build-in IHttpContext interface, not the proper HttpContext.
However I found out that I can cast existing IHttpContext to DotvvmHttpContext which contains property OriginalContext that indeed seems to be the one I was looking for.
var remoteAddr = ((DotvvmHttpContext)Context.HttpContext).OriginalContext.Connection.RemoteIpAddress;
So the question is, if this is "safe" approach or is there any other "proper" way to either access original AspNet HttpContext or the remote IP Address directly?

Yes, this is safe approach as long as you are only going to run the application on Asp.Net Core. If you'd switch to OWIN hosting for some reason, it would throw an invalid cast exception.
Also note that there is a helper method for getting the Asp.Net Core http context, Context.GetAspNetCoreContext().Connection... might be a bit more comfortable. As you can see from the source code, it's basically the same as your code: https://github.com/riganti/dotvvm/blob/d623ae5ddf57ecf3617eb68454d546f675b64496/src/DotVVM.Framework.Hosting.AspNetCore/Hosting/AspNetCoreDotvvmRequestContextExtensions.cs#L13

Looking at the source for IHttpContext that is exposed in the DotvvmViewModelBase, there does not seem to be a good way to access the connection information. I was hoping that the IHttpRequest might expose the remote IP address but that also isn’t the case.
You have to rely on accessing the original HttpContext from ASP.NET Core here to access that information. If you run on ASP.NET Core (instead of OWIN), then it should be totally save to cast the context to DotvvmHttpContext so that you can access the underlying HttpContext.
So yeah, your solution seems just fine here:
var originalHttpContext = ((DotvvmHttpContext)Context.HttpContext).OriginalContext;

Related

Azure fluent management api bind custom root domain to app service

I've been having trouble with this for a while and now I really need help.
This is the code I am currently using to bind a custom subdomain to Azure and everything is working just fine:
var appService = await azure.AppServices.WebApps.GetByIdAsync(
"subscription-id");
await appService.Update().DefineHostnameBinding()
.WithThirdPartyDomain("mydomain.net")
.WithSubDomain("www")
.WithDnsRecordType(CustomHostNameDnsRecordType.CName)
.Attach()
.ApplyAsync();
So what will be the way to bind just mydomain.net except that CustomHostNameDnsRecordType.CName should be changed with CustomHostNameDnsRecordType.A because Azure does not support CNAME records for root domains?
I cannot skip the WithSubDomain(string) method. Tried passing and null/empty string/space or just . but the response from Azure for null is Object reference not set to an instance and for the others is Bad Request.
P.S. I know that I am using an old SDK which is in maintenance mode but the new ones are still in beta or even alpha and there is still no support for App Services so I have to stick with that.
#DeepDave-MT pointed me to the correct answer in a comment under my question even though it's ridiculous. I am now quite sure I will go with this fluent API because there are too many things that are bothering me, almost no documentation, bad error handling and so on. Anyway, this is how to add a root domain in Azure using the so called fluent management API:
await appService.Update().DefineHostnameBinding()
.WithThirdPartyDomain("mydomain.net")
.WithSubDomain("#")
.WithDnsRecordType(CustomHostNameDnsRecordType.A)
.Attach()
.ApplyAsync();
P.S. I don't know why I don't have the habit to check for issues in GitHub.

Generating links to self when running behind reverse proxy

How can I generate absolute links to other resources in my RESTful API app when the app is meant to be accessed via a reverse proxy that publishes just the paths under /api?
My app is an API with a common layout of routes like /api, /swagger and /health. It is published on my employer's API management under a path of the form /business-area/api-name/v1. Calling the API both directly and through the API gateway overall works: calling https://api-gateway.company.com/business-area/api-name/v1/some-resource results in internal call to https://my-app.company.com/api/some-resource.
The issue is that the links in my app's responses point directly to the backend app (https://my-app.company.com/api/another-resource), not the the API gateway (https://api-gateway.company.com/business-area/api-name/v1/another-resource). They are generated using IUrlHelper.
I solved the domain by the ForwardedHeadersMiddleware and adding the X-Forwarded-Host by a policy on the API management. Sadly, we are allowed to use just extremely simple policies, so if we published the API using multiple gateways, the current solution would generate link to just a single one. But that is an issue to be solved somewhen later; now it works OK.
I could not get the path to work well. I tried changing the paths using a middleware as hinted in the ASP.NET Core behind proxy docs:
app.Use((context, next) =>
{
context.Request.PathBase = "/business-area/api-name/v1";
if (context.Request.Path.StartsWithSegments("/api", out var remainder))
{
context.Request.Path = remainder;
}
return next();
});
When I insert this middleware high in the pipeline, it breaks the routing, but if I insert it low enough, the routing works OK and only link generation is affected. But it seems that only PathBase change really affects link generation as the /api is still in the generated URI. I can see that the Path of the request object is really changed, though, so it is probably just that link generation uses the routing info directly, without passing through my middleware, which makes sense, but it rules out the middleware solution.
Is wrapping the standard IUrlHelper in my own implementation and postprocessing the URLs it returns a good way to go? I don't know how to go about that. I use the IUrlHelper from the ControllerBase.Url property and debugger tells it is actually an instance of Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper. Doing the wrapping in every action seems wrong (repetitive, error-prone).
Changing the routing so that /api moves to the root is my last resort option as it mixes up the namespaces: technical endpoints like /health and /swagger would live among the actual resources of the API. Is there a reasonable way to avoid that while keeping the links working? This all seems like a pretty standard problem and I am surprised I cannot find how to solve it.
We use .NET 5 and we will migrate to .NET 6 as soon as it is out, if that makes any difference.

CRM 2013 Get CRM URL via Custom Workflow

I have a requirement for getting a CRM URL via a custom workflow to use in the next step which is to send an email. The reason for this is to differentiate to users which server this email has come from (UAT/Live).
I have been trying to use HTTPContext route as advised from this site https://social.microsoft.com/Forums/en-US/31ff567d-65ea-4385-a764-68a2121ae8c0/ms-crm-2011-get-path-of-crm-server-url-in-plugin?forum=crmdevelopment but the result I get back is useless as I am I am only receiving an "/" back.
Does anyone know what to do from this point or why this may not be working?
This can't be accomplished, in a supported manner, without creating a connection to the CRM Discovery Service, which requires that you supply credentials. The organization service, available in the workflow does not have a method for discovering the organization's URL.
You have two options:
1) Pass it to the workflow as a parameter using the InputParameter code attribute on your CodeActivity.
2) Create (if you don't already have one) a configuration entity to store the URL and retrieve it in your code.
If you don't really need the URL (i.e., you are not creating a link) then you could just query the Organization entity for the Name attribute. That will give you the Organization's name - which would be the only unique part of the URL. This would allow you to indicate to the user if the Email was coming from UAT or Prod.
I ended up coming up with a solution by using the environment.machinename to pull through the server name. From there i could determine which production server the workflow had been run through and passed a string containing, dev, uat or live to the output to use in my activity emails.
Be aware i had to register the workflow without it being in sandbox mode. Hope this helps somebody in the future.
This was an extremely old question but I came across it while attempting to do something similar.
I found that there is a RetrieveCurrentOrganizationRequest request which was introduced in v9. This will work in sandboxed plugins.
You can use this to retrieve the endpoint urls like so
var currentOrg = base.OrgService.Execute(
new RetrieveCurrentOrganizationRequest()
) as RetrieveCurrentOrganizationResponse;
var url = currentOrg.Detail.Endpoints
.Where(e => e.Key == EndpointType.WebApplication)
.FirstOrDefault()
.Value;
More information here: RetrieveCurrentOrganizationRequest
When I used it, I found that there are 3 available URLs in the Endpoints collection:
Web Application
Organization Data Service
Organization Service
Relevant to CRM 2013 (which the OP was using at the time), there is also the RetrieveOrganizationRequest class which does the same as above; however you have to specify the Organization (and some other information)

HttpSelfHostServer and HttpContext.Current

I'm working on a self-hosted ASP.NET web api-application.
Everything works fine, but now I'm struggling with HttpContext:
I need to save session-informations from the client.
But HttpContext.Current is always null.
So it's obvious that my HttpSelfHostServer don't work with the static HttpContext-Class.
The thing I don't understand is: why..?
And I can't figure out a way to tell neither HtttpSelfHostServer nor HttpSelfHostConfiguration to work with HttpContext.
Here's what I'm doing:
Creating a HttpSelfHostConfiguration
1.1 Adding Service-Resolvers & Routes
1.2 Adding custom UserNamePassword-Validator
create new Instance of HttpSelfHostServer with the config
2.1 server.OpenAsync().Wait()
Any help how I can tell my server to work with HttpContext.Current is greatly appreciated!
Cheers!
You won't be able to use HttpContext in a self-hosted environment. HttpContext is set by the ASP.Net pipeline, which you won't have if you don't run under IIS/ASP.Net.
The HttpContext is only available in the Web-Hosting mode, in which the HttpControllerHandler creates the request.
FYI- I invite you to read the following great articles from Pedro Felix to better understand the different hosting models:
HTTP processing architecture overview
Web-hosting
Self-hosting
To get around this problem (I find I am using a lot of components these days that need to work equally well in Web API and MVC), you can try this old shim I wrote to give you back an HttpContext-like interface that works in both flavours. It's on NuGet also, here's the source:
Link on github
(or Link on Nuget)

Determine the URL hostname without using HttpContext.Current?

Using the current request I can get the URL hostname with:
HttpContext.Current.Request.Url.Host
But - I need to determine the URL hostname without using the current request (HttpContext.Current). The reason for this is that my code is called from a SqlDependency in the onChange callback for when a SQL Dependency is found. Althougth the code resides in my web app, there is no request, and HttpContext.Current is null.
I was hoping I could grab it from HttpRuntime, but there doesn't seem to be anything of use there. is there a way I can get this information?
If you are running this from a web application, and it is all managed code then HttpContext must exist. Does your child library (assuming your managed code is in a library) have a reference to System.Web? If not, consider adding this reference. From that point you should be able to access the HttpContext directly by using the fully qualified namespace:
System.Web.HttpContext.Current.Request.Url.Host
In any case, unless your code is unmanaged or your context truly does not originate with a web application, HttpContext should be available at every point while the thread is alive.
Edit:
Based on reading your comment below, it sounds like the SqlDependency is being fired independently. While it's on the same thread, it's not being fired directly by the request. Since all you're looking for is the host url, it's not inconceivable that you can create an application variable or a static variable to hold this information in the event that it is needed for a dependency.
Also something I have seen is that while HttpContext.Current may not be available, HttpContext.Request might be. These should be the same object, but they may not necessarily be. It's possible that the Host may be found there.
How about
Environment.MachineName
If you know the host at the moment you're setting up the event handler then you should be able to do something like (code not actually tested):
string host = HttpContext.Current.Request.Url.Host;
var dep = new SqlDependency(cmd);
dep.OnChange += ((sender, args) =>
{
DoStuff(host);
});
You should use the IIS api to query the information from the website you're looking for. Because depending on the IIS configuration your URL or Hostname could be differing. (Think about hostheaders, ports, protocols and stuff like this.
A introduction for IIS API could be found at http://learn.iis.net/page.aspx/165/how-to-use-microsoftwebadministration/

Categories