-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
In item templates, is it possible to determine things like project name / namespace? #338
Comments
Hi @tintoy, these values can be accepted via parameters but cannot be figured out automatically at this time. As far as the usage of these names go (file names/namespaces/literal strings/etc), we're tracking the work to make that possible with #141. For collecting the name of the project in the target directory, this could be done with implementations of Without these, in terms of how you'd handle this if the user provided the parent namespace, let's say you had the following layout on disk
Let's also say that namespace Company.Application.Classes
{
public class TheClass
{
}
} If you want to use the parent project's namespace rather than "symbols": {
"ParentProjectNamspace": {
"type": "parameter",
"replaces": "Company.Application",
"dataType": "string",
"defaultValue": "Company.Application"
}
} With this, if the user did something like this namespace Project1.Stuff.Classes
{
public class Hello
{
}
} |
Thanks, that's super useful! :) I might start experimenting with this on one of my simpler templates for now (a binary PowerShell Core module), which the above should probably cover nicely. And I'll spend this weekend taking a closer look at the extensibility stuff from #286. |
Moving this to the backlog as this may be something interesting to add as a "generated" type symbol that would know how to look at existing content to try to determine the namespace. With the new fallback symbols, the user would still be able to override the value. |
Yeah this will be interesting and important. Not sure how to solve this in a good way though. |
I'm not sure how set in stone the template.json schema is. It would seem to me, if you could add a parameter to the schema that would allow the template generator to know it needs to go look for a project file and grab the root namespace that would certainly help. |
Properties can be added as they won't be understood by older versions. However, the approach mentioned doesn't require a schema modification (it fits nicely within the existing extensibility model); it's also the approach used for port generation & has evolution steps planned to pretty up the syntax. Moreover, for .NET Core, the namespace isn't usually defined in the project file, the tooling makes some inferences about the project name & locations of the files relative to it to determine the target namespace. Even if that were reliably present, to keep item namespaces consistent with the convention being used in the user's existing artifacts, it should really be looking at the peer code files in the target location to make the determination as to what the target namespace is. This means that, whatever the component is that gets built, it'll need to understand the target language(s) for the template & be able to reason about the computed value (thinking of "flat namespace" projects which would normally conflict with item templates with opinionated namespacing for files generated into multiple directories). |
This is currently affecting the |
Having done a bunch of work with the MSBuild engine recently, I think I'm fairly confident that I know how to evaluate / compute the project namespace for a given folder location. If you guys are interested, I could take a look at implementing a symbol generator to do this. |
Root namespace (in fallback order):
Relative namespace:
|
(and it's not hard to use |
That'd be nice but, since Visual Studio doesn't do this either, not having it still keeps this at parity with the in-GUI experience :) |
Ok, so here's a quick proof-of-concept: using Microsoft.Build.Evaluation;
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
namespace FileNSDemo
{
static class Program
{
static void Main(string[] args)
{
try
{
FileInfo targetFile = new FileInfo(args[0]);
Project owningProject = GetOwningProject(targetFile);
if (owningProject == null)
return;
string fileNamespace = owningProject.GetPropertyValue("RootNamespace");
if (String.IsNullOrWhiteSpace(fileNamespace))
fileNamespace = Path.GetFileNameWithoutExtension(owningProject.FullPath);
string relativeDirectory = Path.GetRelativePath(owningProject.DirectoryPath, targetFile.Directory.FullName);
if (relativeDirectory != ".")
fileNamespace += "." + relativeDirectory.Replace(Path.DirectorySeparatorChar, '.');
Console.WriteLine("File '{0}' is owned by project '{1}' (namespace would be '{2}').",
targetFile.FullName,
owningProject.FullPath,
fileNamespace
);
}
catch (Exception unexpectedError)
{
Console.WriteLine(unexpectedError);
}
}
static Project GetOwningProject(FileInfo file)
{
DirectoryInfo directory = file.Directory;
if (!directory.Exists)
{
Console.WriteLine("Directory '{0}' does not exist.", directory.FullName);
return null;
}
while (directory != null)
{
FileInfo projectFile = directory.EnumerateFiles("*.*proj").FirstOrDefault();
if (projectFile != null)
{
string fileRelativePath = file.FullName.Substring(directory.FullName.Length + 1);
using (ProjectCollection projectCollection = MSBuildHelper.CreateProjectCollection(directory.FullName))
{
Project project = projectCollection.LoadProject(projectFile.FullName);
ICollection<ProjectItem> matchingFileItems = project.GetItemsByEvaluatedInclude(fileRelativePath);
if (matchingFileItems.Count > 0)
return project;
}
}
directory = directory.Parent;
}
return null;
}
}
} (fully functional example here) |
Thanks for the PoC @tintoy, I'm hesitant to take a dependency on MSBuild here though due to coordination concerns with all the different release vehicles for this project. |
Yeah, I think I see what you're getting at :) Then again, given that |
Actually, I think I now get where you're coming from - the issue is distributing the MSBuild engine alongside |
This issue was last touched some years ago. We are working on a new delivery road map. Please reopen if this is something we want & we'll properly assess its' priority compared to other work aimed at improving the overall templating UX. |
Yes, I'd like this re-opened, please! Please can I have something that can evaluate anything MSBuild can evaluate? The dotnet new template approach of letting me use compileable code as a template is a brilliant improvement on old-style templates. But this poses challenges for item templates in particular.
Without some kind of evaluator able to do string manipulation and/or variables and/or everything that an msbuild expression can do, item templates for code are semi-automated-semi-manual needs editing after running the template? |
Reviving this issue, imo it makes a lot of sense. @KathleenDollard could you please take a look? |
This is absolutely needed as I'm creating and distributing item templates for .NET MAUI, in which C# classes (both code-behind for XAML style definition and Direct C# style definition) require the C# class type a namespace. At present, managing it as user input and that's not the ideal way to do it as the chances of making an error is high. Unable to implicitly look up the value, my suggestion would be to expose the That would ease out the job. Also, other MSBuild properties can also be exposed as binding symbols. Notify to @sayedihashimi Regards, |
We talked about this recently, I believe that the associated work that is needed is described at #3107. |
This will be implemented in #3829 |
Closed in #3829 |
Hi.
I've been wanting to build item templates for MVC controllers and views, but these require knowledge of things like the current project namespace (or, for nested folders, something even more complex, like joining sub-folders onto that as sub-namespaces).
I've had a browse through the code, but haven't found anything like that (apart from perhaps replacing the entire project name with the target project name, even in source code?) so before I go any further, I wanted to check if this is supposed to be a supported scenario.
Thanks,
Adam.
The text was updated successfully, but these errors were encountered: