I work with Umbraco from Console application.
When I try get NiceUrl for some node it is impossible because UmbracoContext.Current is null.
I can get node path with ids like this: "-1,1067,1080", but don't know how convert it in url format.
How Can I get NiceUrl for Node in console application?
I did next:
In my console application I get node by Id, simple like this:
Node someNode = new Node(nodeId);
When I try get NiceUrl:
string url = someNode.NiceUrl;
get ArgumentNullException.
I checked why it: found next answer NiceUrl uses UmbracoContext so it is not possible because it's null.
Also I can't use this: UmbracoContext.Current.ContentCache.GetById(someidhere).Url
Thanks.
Without the UmbracoContext I don't think it's possible in V6 to get the URL of an IContent node.
I looked through the Umbraco source code and decided to recreate the way it's done there. I came up with this, which worked for my needs.
https://gist.github.com/petergledhill/ca2a3a0ea81b06abcb08
public static class ContentExtensions
{
public static string RelativeUrl(this IContent content)
{
var pathParts = new List<string>();
var n = content;
while (n != null)
{
pathParts.Add(n.UrlName());
n = n.Parent();
}
pathParts.RemoveAt(pathParts.Count() - 1); //remove root node
pathParts.Reverse();
var path = "/" + string.Join("/", pathParts);
return path;
}
public static string UrlName(this IContent content)
{
return new DefaultUrlSegmentProvider().GetUrlSegment(content).ToLower();
}
}
Yes, you can't use: UmbracoContext.Current.ContentCache because this is accessing the same context.
It looks like you are using v6+, so instead you will need to use the API services that Umbraco provide, specifically the ContentService.
There is a thread here that looks into the same thing you are asking: http://our.umbraco.org/forum/developers/api-questions/37981-Using-v6-API-ContentService-in-external-application
And an example of a solution here: https://github.com/sitereactor/umbraco-console-example
Related
Question:
Is there a way how to get the Caller or current frame source code location without using the CallerFilePath attribute?
Background:
I have this helper defined:
public class PathHelper
{
public static string GetThisFilePath([CallerFilePath] string path = null)
{
return path;
}
}
That can be called as follows to obtain the location of source code used to build the binary:
var currentSourceFilePath = PathHelper.GetThisFilePath();
This works fine, unless I have DeterministicSourcePaths turned on (typically via ContinuousIntegrationBuild msbuild property). In such a case the returned paths are trimmed to something like:
/_/MyRelativeSourcePath
So it seems that determinist paths are injected into the compiler functionality supporting CallerFilePath yielding this behavior.
I need the source code location in order to be able to unit test product specific functionality (that has to do with inspecting build process), while I'd still like to support fully determinisitc build on CI machines.
You may try something like following. Please note
this is just an idea, exact implementation depends on your environment
This would be working if you are using "default build output paths" only
I didn't tested it
public static string GetThisFilePath([CallerFilePath] string path = null)
{
const string determenisticRoot = "/_/";
if(!path.StartsWith(determenisticRoot))
{
return path;
}
// callerBinPath would be something like $(SolutionRoot)/.../MyProject.Tests/bin/Debug/net5.0
var callerBinPath = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
// Traverse to $(TestProjectRoot) - testProjectRoot would be something like $(SolutionRoot)/.../MyProject.Tests
var testProjectRoot = Path.Combine(callerExecutablePath, "../../..");
// Combine projectRoot root with relative path from [CallerFilePath]
return Path.Combine(testProjectRoot, path.Substring(determenisticRoot.Length));
}
I want to get from this
"../lib/../data/myFile.xml"
to this
"../data/myFile.xml"
I guess I could do it by manipulating the string, searching for "../" and canceling them out with the preceding folders but I was looking for an already existing C# solution.
Tried instantiating an Uri from this string and going back toString(). Didn't help. It leaves the string unchanged.
You can always try to use:
Path.GetFullPath("../lib/../data/myFile.xml")
It behaves as you want with absolute paths but you might end up with strange behaviors with relative paths since it always bases itself from the current working directory. For instance:
Path.GetFullPath("/lib/../data/myFile.xml") // C:\data\myFile.xml
Path.GetFullPath("../lib/../data/myFile.xml") // C:\Program Files (x86)\data\myFile.xml
Sounds like you may either need to parse/rebuild the path yourself, or use some kind of well constructed regular expression to do this for you.
Taking the parse/rebuild route, you could do something like:
public static string NormalisePath(string path)
{
var components = path.Split(new Char[] {'/'});
var retval = new Stack<string>();
foreach (var bit in components)
{
if (bit == "..")
{
if (retval.Any())
{
var popped = retval.Pop();
if (popped == "..")
{
retval.Push(popped);
retval.Push(bit);
}
}
else
{
retval.Push(bit);
}
}
else
{
retval.Push(bit);
}
}
var final = retval.ToList();
final.Reverse();
return string.Join("/", final.ToArray());
}
(and yes, you'd probably want better variable names/commenting/etc.)
You can use a regular expression to do this:
public static string NormalisePath(string path)
{
return new Regex(#"\.{2}/.*/(?=\.\.)").Replace(path, "");
}
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.
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);
}
I have a website which has two parts: the first one was made in Umbraco CMS (v4.7), the second one in ASP.NET.
The task is to get a sitemap (not just names of pages, I need some parameters as well) in ASP.NET part from Umbraco.
I have only one idea how I can do such thing - write an XML file in Umbraco and then open it in ASP.NET, but I did not find any way how exactly do it.
If you have any ideas, please help.
Many Thanks
Vlad
you can do something like this...
using umbraco.presentation.nodeFactory;
public string CreateSitemap()
{
var temp = "<ul>" + sitemap(-1) + "</ul>";
return temp;
}
public string sitemap(int nodeID)
{
var rootNode = new umbraco.presentation.nodeFactory.Node(nodeID);
string sitemapstring = "<li>" + rootNode.Name + "</li>";
if(rootNode.Children.Count>0)
{
sitemapstring+="<ul>";
foreach(Node node in rootNode.Children)
{
sitemapstring += sitemap(node.Id);
}
sitemapstring+="</ul>";
}
return sitemapstring;
}
Maybe you should check out the Razor edition of this sitemap package (at the bottom)?