Recently working on a ASPCore Web Api (C#) I wanted to add a version endpoint so I can tell which version of a given API Im working with. Its a public API so I don't want to include things that might be used to determine vulnerabilities such as third party package version etc.
So far I've got the Following.
// GET api/values
[HttpGet]
public string Get()
{
var attributes = Assembly.GetEntryAssembly().CustomAttributes;
string versionInfo=null;
foreach(var attribute in attributes)
{
if (attribute.AttributeType.Name.StartsWith("Assembly")&& attribute.AttributeType.Name.EndsWith("Attribute"))
{
string name = attribute.AttributeType.Name;
name = name.Substring(8, name.Length - 17);
versionInfo = string.Concat(versionInfo, name, ":");
versionInfo = string.Concat(versionInfo, attribute.ConstructorArguments.FirstOrDefault());
versionInfo = string.Concat(versionInfo, System.Environment.NewLine);
}
}
return versionInfo;
}
which Produces
Company:"Company Name"
Configuration:"Debug"
Description:"Package Description"
FileVersion:"0.0.1.0"
InformationalVersion:"0.0.1"
Product:"ProductName"
Title:"PackageTitle"
Is there any more industry standard approach to this. Seems it would be a fairly standard issue but Im not seeing any sort of standard way to accomplish this from my brief date with Google.
Related
Is there any way in ASP.net C# to treat sub-domain as query string?
I mean if the user typed london.example.com then I can read that he is after london data and run a query based on that. example.com does not currently have any sub-domains.
This is a DNS problem more than an C#/ASP.Net/IIS problem. In theory, you could use a wildcard DNS record. In practice, you run into this problem from the link:
The exact rules for when a wild card will match are specified in RFC 1034, but the rules are neither intuitive nor clearly specified. This has resulted in incompatible implementations and unexpected results when they are used.
So you can try it, but it's not likely to end well. Moreover, you can fiddle with things until it works in your testing environment, but that won't be able to guarantee things go well for the general public. You'll likely do much better choosing a good DNS provider with an API, and writing code to use the API to keep individual DNS entries in sync. You can also set up your own public DNS server, though I strongly recommend using a well-known and reputable commercial DNS host.
An additional problem you can run into is the TLS/SSL certificate (because of course you're gonna use HTTPS. Right? RIGHT!?) You can try a wild card certificate and probably be okay, but depending on what else you do you may find it's not adequate; suddenly you're needing to provision a separate SSL certificate for every city entry in your database, and that can be a real pain, even via the Let's Encrypt service.
If you do try it, IIS is easily capable of mapping the requests to your ASP.Net app based on a wildcard host name, and ASP.Net itself is easily capable of reading and parsing the host name out of the request and returning different results based on that. IIS URL re-writing should be able to help with this, though I'm not sure whether you can do stock MVC routing in C#/ASP.Net based on this attribute.
I have to add to the previous answers, that after you fix the dns, and translate the subdomain to some parameters you can use the RewritePath to move that parameters to your pages.
For example let say that a function PathTranslate(), translate the london.example.com to example.com/default.aspx?Town=1
Then you use the RewritePath to keep the sub-domain and at the same time send your parameters to your page.
string sThePathToReWrite = PathTranslate();
if (sThePathToReWrite != null){
HttpContext.Current.RewritePath(sThePathToReWrite, false);
}
string PathTranslate()
{
string sCurrentPath = HttpContext.Current.Request.Path;
string sCurrentHost = HttpContext.Current.Request.Url.Host;
//... lot of code ...
return strTranslatedUrl
}
A low tech solution can be like this: (reference: https://www.pavey.me/2016/03/aspnet-c-extracting-parts-of-url.html)
public static List<string> SubDomains(this HttpRequest Request)
{
// variables
string[] requestArray = Request.Host().Split(".".ToCharArray());
var subDomains = new List<string>();
// make sure this is not an ip address
if (Request.IsIPAddress())
{
return subDomains;
}
// make sure we have all the parts necessary
if (requestArray == null)
{
return subDomains;
}
// last part is the tld (e.g. .com)
// second to last part is the domain (e.g. mydomain)
// the remaining parts are the sub-domain(s)
if (requestArray.Length > 2)
{
for (int i = 0; i <= requestArray.Length - 3; i++)
{
subDomains.Add(requestArray[i]);
}
}
// return
return subDomains;
}
// e.g. www
public static string SubDomain(this HttpRequest Request)
{
if (Request.SubDomains().Count > 0)
{
// handle cases where multiple sub-domains (e.g. dev.www)
return Request.SubDomains().Last();
}
else
{
// handle cases where no sub-domains
return string.Empty;
}
}
// e.g. azurewebsites.net
public static string Domain(this HttpRequest Request)
{
// variables
string[] requestArray = Request.Host().Split(".".ToCharArray());
// make sure this is not an ip address
if (Request.IsIPAddress())
{
return string.Empty;
}
// special case for localhost
if (Request.IsLocalHost())
{
return Request.Host().ToLower();
}
// make sure we have all the parts necessary
if (requestArray == null)
{
return string.Empty;
}
// make sure we have all the parts necessary
if (requestArray.Length > 1)
{
return $"{requestArray[requestArray.Length - 2]}.{requestArray[requestArray.Length - 1]}";
}
// return empty string
return string.Empty;
}
Following question is similar to yours:
Using the subdomain as a parameter
Can any one suggest another way to integrate NodeJs in .Net MVC application? I am now using the following code:
public class Startup
{
public async Task<object> Invoke(dynamic input)
{
DepartmentRep person = new DepartmentRep(new MvcAppUsingEdgeJSMongoDbContext());
var department= person.GetAllDepartments();
//var department = "hello";
return department;
}
}
public class DepartmentController : Controller
{
DepartmentRepository departmentRepository = new DepartmentRepository(new MvcAppUsingEdgeJSMongoDbContext());
string connectionString = ConfigurationManager.AppSettings["connectionString"].ToString();
public ViewResult Index()
{
// var clrMethod = Edge.Func("DepartmentRep.cs");
var getData = Edge.Func("./DepartmentRep.dll");
// return View(clrMethod);
return View(departmentRepository.GetAllDepartments());
}
}
It seems to me, you may have a misunderstanding of the EdgeJs use case.
Your Startup/Invoke class/Signature is meant to be called from Node(JavaScript),
And from the code you are showing it looks like you are loading .Net from .Net
Also , as the Invoke signature suggest, It should be asynchronous.
If you want to use node from .Net side. You should check the project documentation from
scripting-nodejs-from-clr downwards.
var func = Edge.Func(#"
return function (data, callback) {
callback(null, 'Node.js welcomes ' + data);
}
");
As you can see there the wrapped code is Javascript, this time running in .Net more specifically running in Node.
The perfect use case IMMO is the Socket-Server, that is, something Node does better than .Net (IMMO again)
Which is in perfect contrast with the .Net Ado Sql Server access from NodeJs, a .Net Specialization from NodeJs context
Given a URL as follows:
foo.bar.car.com.au
I need to extract foo.bar.
I came across the following code :
private static string GetSubDomain(Uri url)
{
if (url.HostNameType == UriHostNameType.Dns)
{
string host = url.Host;
if (host.Split('.').Length > 2)
{
int lastIndex = host.LastIndexOf(".");
int index = host.LastIndexOf(".", lastIndex - 1);
return host.Substring(0, index);
}
}
return null;
}
This gives me like foo.bar.car. I want foo.bar. Should i just use split and take 0 and 1?
But then there is possible wwww.
Is there an easy way for this?
Given your requirement (you want the 1st two levels, not including 'www.') I'd approach it something like this:
private static string GetSubDomain(Uri url)
{
if (url.HostNameType == UriHostNameType.Dns)
{
string host = url.Host;
var nodes = host.Split('.');
int startNode = 0;
if(nodes[0] == "www") startNode = 1;
return string.Format("{0}.{1}", nodes[startNode], nodes[startNode + 1]);
}
return null;
}
I faced a similar problem and, based on the preceding answers, wrote this extension method. Most importantly, it takes a parameter that defines the "root" domain, i.e. whatever the consumer of the method considers to be the root. In the OP's case, the call would be
Uri uri = "foo.bar.car.com.au";
uri.DnsSafeHost.GetSubdomain("car.com.au"); // returns foo.bar
uri.DnsSafeHost.GetSubdomain(); // returns foo.bar.car
Here's the extension method:
/// <summary>Gets the subdomain portion of a url, given a known "root" domain</summary>
public static string GetSubdomain(this string url, string domain = null)
{
var subdomain = url;
if(subdomain != null)
{
if(domain == null)
{
// Since we were not provided with a known domain, assume that second-to-last period divides the subdomain from the domain.
var nodes = url.Split('.');
var lastNodeIndex = nodes.Length - 1;
if(lastNodeIndex > 0)
domain = nodes[lastNodeIndex-1] + "." + nodes[lastNodeIndex];
}
// Verify that what we think is the domain is truly the ending of the hostname... otherwise we're hooped.
if (!subdomain.EndsWith(domain))
throw new ArgumentException("Site was not loaded from the expected domain");
// Quash the domain portion, which should leave us with the subdomain and a trailing dot IF there is a subdomain.
subdomain = subdomain.Replace(domain, "");
// Check if we have anything left. If we don't, there was no subdomain, the request was directly to the root domain:
if (string.IsNullOrWhiteSpace(subdomain))
return null;
// Quash any trailing periods
subdomain = subdomain.TrimEnd(new[] {'.'});
}
return subdomain;
}
You can use the following nuget package Nager.PublicSuffix. It uses the PUBLIC SUFFIX LIST from Mozilla to split the domain.
PM> Install-Package Nager.PublicSuffix
Example
var domainParser = new DomainParser();
var data = await domainParser.LoadDataAsync();
var tldRules = domainParser.ParseRules(data);
domainParser.AddRules(tldRules);
var domainName = domainParser.Get("sub.test.co.uk");
//domainName.Domain = "test";
//domainName.Hostname = "sub.test.co.uk";
//domainName.RegistrableDomain = "test.co.uk";
//domainName.SubDomain = "sub";
//domainName.TLD = "co.uk";
private static string GetSubDomain(Uri url)
{
if (url.HostNameType == UriHostNameType.Dns)
{
string host = url.Host;
String[] subDomains = host.Split('.');
return subDomains[0] + "." + subDomains[1];
}
return null;
}
OK, first. Are you specifically looking in 'com.au', or are these general Internet domain names? Because if it's the latter, there is simply no automatic way to determine how much of the domain is a "site" or "zone" or whatever and how much is an individual "host" or other record within that zone.
If you need to be able to figure that out from an arbitrary domain name, you will want to grab the list of TLDs from the Mozilla Public Suffix project (http://publicsuffix.org) and use their algorithm to find the TLD in your domain name. Then you can assume that the portion you want ends with the last label immediately before the TLD.
I would recommend using Regular Expression. The following code snippet should extract what you are looking for...
string input = "foo.bar.car.com.au";
var match = Regex.Match(input, #"^\w*\.\w*\.\w*");
var output = match.Value;
In addition to the NuGet Nager.PubilcSuffix package specified in this answer, there is also the NuGet Louw.PublicSuffix package, which according to its GitHub project page is a .Net Core Library that parses Public Suffix, and is based on the Nager.PublicSuffix project, with the following changes:
Ported to .NET Core Library.
Fixed library so it passes ALL the comprehensive tests.
Refactored classes to split functionality into smaller focused classes.
Made classes immutable. Thus DomainParser can be used as singleton and is thread safe.
Added WebTldRuleProvider and FileTldRuleProvider.
Added functionality to know if Rule was a ICANN or Private domain rule.
Use async programming model
The page also states that many of above changes were submitted back to original Nager.PublicSuffix project.
Is is possible to use Actionmailer.Net.Standalone in a console application? I keep getting an error that:
Could not find any CSHTML or VBHTML views named [CRD.html.cshtml] in the path [EmailTemplates]. Ensure that you specify the format in the file name (ie: CRD.html.cshtml.txt.cshtml or CRD.html.cshtml.html.cshtml)
Code
public class Mailer : RazorMailerBase
{
public override string ViewPath
{
get { return "EmailTemplates"; }
}
public RazorEmailResult Processed(string f)
{
From = group;
To.Add(user);
Subject = "CRD Process Server has processed file: " + f;
return Email("CRD.html.cshtml");
}
}
Do I need to implement a RazorViewEngine somewhere since it isn't standard with a console application?
A little late but maybe it still helps:
Try to change
return Email("CRD.html.cshtml");
to
return Email("CRD");
The extensions are appenden automatically.
There is a open source project as a general templating engine called RazorEngine
A templating engine built upon Microsoft's Razor parsing technology.
The RazorEngine allows you to use Razor syntax to build robust
templates.
Simply;
string template = "Hello #Model.Name! Welcome to Razor!";
string result = Razor.Parse(template, new { Name = "World" });
Also available in NuGet;
Install-Package RazorEngine
I'm working with C# and the .NET 2.0 framework in Visual Studio 2010.
I'm trying to extract a URL which is returned by a web service.
This URL is returned in an array of features containing keys and values. (I think this is similar to what I learned in school is called a hash table).
My intellisense doesn't pick up anything useful and I can't figure out what I'm doing wrong.
This is the code. What goes in serverInfo.FeatureSet[]?
public string wfl_reqURL(string username, string password)
{
MyWorkflow.ServerInfo serverInfo = new MyWorkflow.ServerInfo();
myURL = serverInfo.FeatureSet[];
}
This is how it's described in the WSDL. FeatureSet is being returned as an array with a string key and a string value:
<ServerInfo>
<FeatureSet>
<Feature>
<Key>FileUploadUrl</Key>
<Value>http://localhost/transferindex.php</Value>
</Feature>
</FeatureSet>
</ServerInfo>
Have I provided enough detail about my problem? Most of the information I've found seems to be about how to create such arrays in web services, not select one from a web service as I'd like to do.
Try something like this:
object neededItem = null;
foreach (string item in serverInfo.FeatureSet.Keys)
{
if (item == "FileUploadUrl")
{
neededItem = serverInfo.FeatureSet[item];
break;
}
}
if (neededItem != null)
{
//Do something
}
If you're using c# 3.5 then something in linq like
myURL = serverInfo.FeatureSet.First(o=>o.Key == "FileUploadUrl").Value
The problem was in the data type. Changing the code to this solved the problem, albeit in a messy way. I thought it had something to do with types and how it was defined...either as dictionary or arrays, but it was a bit different than I'd thought...
foreach( MyWorkFlow.Feature feature in serverInfo.FeatureSet) {
if (feature.Key.ToString() == "FileUploadUrl") {
string myURL = feature.Value;
Console.WriteLine(myURL);
}