Hosting StyleCop in a Custom Environment - c#

I want to host StyleCop in a Custom Environment, the sample code provided in SDK uses this foreach(string myProject in this.myProjects). String doesn't have properties like Path.GetHashCode() and FilesToAnalyze, does anyone knows what is this.myProjects?
List<CodeProject> projects = new List<CodeProject>();
// what is this.myProject?
foreach (string myProject in this.myProjects)
{
CodeProject project = new CodeProject(
myProject.Path.GetHashCode(), myProject.Path, configuration);
// Add each source file to this project.
foreach (string sourceFilePath in myProject.FilesToAnalyze)
{
console.Core.Environment.AddSourceCode(project, sourceFilePath, null);
}
projects.Add(project);
}

After looking at the example in the SDK I think myProject is just a placeholder to indicate how to construct a CodeProject instance.
If you want you can define a class as shown below or keep the root path and files to analyze in a different data structure.
public class MyProject
{
public string Path { get { ... } }
public IEnumerable<string> FilesToAnalyze { get { ... } }
}

Yes, this is just meant to be a pseudocode example. Your best bet it to go to stylecop.codeplex.com and just look at the actual StyleCop code. There are many examples in the code showing how to host StyleCop.

Related

Add [ApiController] Attribute to the class

I have implemented the project of migrating Asp.Net WebApi into Asp.Net Core 3.1.I have started to learning the Rosyln parser. Using Rosyln, I have to change "ApiController" property into attribute in the class name.
Sample.cs
namespace TestFile.TestData.Target
{
public class SampleFile: ApiController
{
}
}
into
namespace TestFile.TestData.Target
{
[ApiController]
public class SampleFile: ControllerBase
{
}
}
I have followed the link :
Adding custom attributes to C# classes using Roslyn. but didn't understand.
Kindly suggest on alternative solution on how to do using Roslyn.
What are you trying to achvieve? You have successfully added [ApiController] there is no more extra steps. The link is about adding attribute via source generetor (code that writes code) if you are just trying to add attribute you don't need source generators.
Btw Roslyn is name of the c# compiler. Wich is used to creating your entire application, not a tool for adding attributes to a class :)
If you are trying to generate class via source generators maybe edit the question a little bit
Finally I got this,
Sample.cs:
private void AddCustomClassAttribute(string TargetClassFile, string CustomAttributeName)
{
var code = File.ReadAllText(TargetClassFile);
var updateClassFile = InsertClassAttribute(code, CustomAttributeName).GetAwaiter().GetResult();
if (!string.IsNullOrEmpty(updateClassFile))
File.WriteAllText(TargetClassFile, updateClassFile);
}
private async Task<string> InsertClassAttribute(string Code, string CustomAttributeName)
{
// Parse the code into a SyntaxTree.
var tree = CSharpSyntaxTree.ParseText(Code);
// Get the root CompilationUnitSyntax.
var root = await tree.GetRootAsync().ConfigureAwait(false) as CompilationUnitSyntax;
var findNamespace = root.Members.Single(m => m is NamespaceDeclarationSyntax) as NamespaceDeclarationSyntax;
// Get all class declarations inside the namespace.
var classDeclarations = findNamespace.Members.Where(m => m is ClassDeclarationSyntax);
// find the main class from the findNameSapce
var findRootClass = classDeclarations.First() as ClassDeclarationSyntax;
var addCustomAttribute = AttributeList(
SingletonSeparatedList(
Attribute(IdentifierName(CustomAttributeName)))
).NormalizeWhitespace();
// To check whether specific attribute is present in the class or not then only insert given attribute
if (findRootClass.BaseList?.Types.ToFullString().Trim() == CustomAttributeName)
{
var attributes = findRootClass.AttributeLists.Add(addCustomAttribute);
root = root.ReplaceNode(
findRootClass,
findRootClass.WithAttributeLists(attributes)).NormalizeWhitespace();
return root.ToFullString();
}
return null;
}

How to get current folder from a C# static class on Unity

I imported a Unity package where several Editor scripts depend on a RootPath property from a static class:
public static class EditorUtils
{
public static string RootPath => "Assets/HardcodedPath";
}
The problem is that this path is hardcoded, so that the package location can't be changed at all. I plan on changing the RootPath property so that it gets the current script location and searches for parent folder with a given pattern. That way, I would be able to use this package even inside a custom package of my own (inside a Packages folder instead of the Assets folder, that is).
The missing piece is that I can't find a way to get this static class folder location from code. Can anyone help me with this?
Dig around through the AssetDatabase and find a reference to your script. This should return what you're wanting.
public static class EditorUtils
{
public static string RootPath
{
get
{
var g = AssetDatabase.FindAssets ( $"t:Script {nameof(EditorUtils)}" );
return AssetDatabase.GUIDToAssetPath ( g [ 0 ] );
}
}
}
That will also hold true for scripts in Packages.
Remember to change EditorUtils to your script name.
Here's the relevant Unity docs.

Alternative name of a field for UI purposes

I want to give a field (or property) an alternative name that can be shown in the user interface by using reflection. I have found the attribute DescriptionAttribute, but is it really for this purpose or am I better off using something else?
Is this attribute somehow restricted to Windows Forms and its property view, or is it UI framework independent? (currently I am on Windows Forms for the project, but it might change in the future so I don't want to be stuck with it)
public class MyCustomZoo
{
[Description("Cute Mouse")]
public MyCustomAnimal CuteMouse;
[Description("Frightning Lion")]
public MyCustomAnimal FrightningLion;
}
I have found my preferred solution in one of the answers here.
using System.ComponentModel.DataAnnotations;
// ...
public class MyCustomZoo
{
[Display(Name = "Cute Mouse")]
public object CuteMouse;
[Display(Name = "Frightning Lion")]
public int FrightningLion;
}
public static string FieldDisplayName(FieldInfo field)
{
DisplayAttribute da = (DisplayAttribute)(field.GetCustomAttributes(typeof(DisplayAttribute), false)[0]);
return da.Name;
}
// ...
// c# identifier names, results in {"CuteMouse","FrightningLion"}
List<string> fieldNames = typeof(MyCustomZoo).GetFields().Select(field => field.Name).ToList();
// "human readable" names, results in {"Cute Mouse","Frightning Lion"}
List<string> fieldDisplayNames = typeof(MyCustomZoo).GetFields().Select(field => FieldDisplayName(field)).ToList();
Don't forget to add a reference to assembly System.ComponentModel.DataAnnotations.
Note: System.ComponentModel.DisplayNameAttribute could be used as well (thanks to Kieran Devlin) if properties is what you want to tag. With pure fields it doesn't work however.

How can i go back a level when specifying a path in C#?

I want to programmatically install a folder in Visual Studio's "Extensions" folder. The closest i can get is using the VS100COMNTOOLS environment variable. What i want to do is go back one level from the "Tools" folder, the go into IDE/Extensions, something like VS100COMNTOOLS..\IDE\Extensions. This is my code:
namespace TemplatesCustomAction
{
public class CustomActions
{
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
var vspath = Environment.GetEnvironmentVariable("VS100COMNTOOLS");
session["VSINSTALLATIONFOLDER"] = string.Format(#"{0}\..\IDE\Extensions", vspath);
return ActionResult.Success;
}
}
}
Use Path.GetFullPath:
var pathWithParent = string.Format(#"{0}\..\IDE\Extensions", vspath);
session["VSINSTALLATIONFOLDER"] = Path.GetFullPath(pathWithParent);
Though I'd also rather use Path.Combine:
var pathWithParent = Path.Combine(vspath, #"\..\IDE\Extensions");

ApplicationSettingsBase and XmlSerialization not working without using csc.exe on a Merged executable

I try to save some application data using ApplicationSettingsBase class's Save method. I have a net 2.0 exe (BugTest.exe) and a net 2.0 dll (MyLibrary.dll). Exe is using dll (references it). My main exe code is like that:
public class ApplicationSettings : ApplicationSettingsBase
{
[UserScopedSetting]
[DefaultSettingValue(null)]
public Settings Settings
{
get
{
return ((Settings)this["Settings"]);
}
set
{
this["Settings"] = value;
}
}
[UserScopedSetting]
[DefaultSettingValue(null)]
public LibrarySettings LibrarySettings
{
get
{
return ((LibrarySettings)this["LibrarySettings"]);
}
set
{
this["LibrarySettings"] = value;
}
}
}
public class Settings
{
public string FirstValue { get; set; }
public string LastValue { get; set; }
}
private void btnSave_Click(object sender, EventArgs e)
{
Settings settings = new Settings {FirstValue = "1", LastValue = "2"};
LibrarySettings librarySettings = new LibrarySettings { LibrarySettings1Value = "1", LibrarySettings2Value = "2" };
ApplicationSettings applicationSettings = new ApplicationSettings {Settings = settings, LibrarySettings = librarySettings};
applicationSettings.Save();
}
And MyLibrary.dll code is:
public class LibrarySettings
{
public string LibrarySettings1Value { get; set; }
public string LibrarySettings2Value { get; set; }
}
It's important for me to use pre-built xmlSerialization dlls for my project. So, then I add “$(FrameworkSDKDir)\Bin\sgen” /a:"$(TargetPath)" /force Post-built event command line (both for exe and dll). Then I got two xmlSerialization dll on my release directory: (BugTest.XmlSerializers.dll and MyLibrary.XmlSerializers.dll)
I start my application and start process monitor. Everything is ok and my application settings are saved succesfully. And I see that csc.exe (run time compiler) never run during serialization. It's also important for me to making Xmlserialization without csc.exe. So everything is well for me.
Also on my project I've to merge BugTest.exe and Mylibrary.dll. So I use ILMerge and merged BugTest.exe and MyLibrary.dll. Output is BugTest.exe. (BugTest.XmlSerializers.dll and MyLibrary.XmlSerializers.dll are not merged.) When I run and click save button of this merged BugTest.exe, saving application data to file is possible again but process monitor screen alert me that this xmlserialization maked by csc.exe. BugTest.XmlSerializers.dll and MyLibrary.XmlSerializers.dll are in the same directory with BugTest.exe but why my application using csc.exe for XmlSerialization this time instead of XmlSerializers.dlls ?
How can I force merged executable to use XmlSerializers.dlls ?
NOTE: Because of OOP design, I shouldn't carry LibrarySettings class codes from MyLibrary.dll to the BugTest.exe codes.
I've just solved this problem by changing order of some processes.
If I compile the project without generating XMLSerialization dlls and then merge BugTest.exe and MyLibrary.dll as a new BugTest.exe and then generate BugTest.XmlSerialization.dll from this new BugTest.exe (using sgen) then my application works perfectly.
This post http://blog.bits-in-motion.com/2009/11/xmlserializers-moduleversionid-ilmerge.html is very useful for my solution.

Categories