Roslyn CodeFix with multiple variants to fix - c#

I have a CodeFix provider, purpose of which to inject service to current class, like add new private field, parameter to constructor, assignment statement in constructor, using ServiceNamespace, and use of this field in proper place(s).
At some point, I have a name of this service, and I need to find namespace for this service to add correct using. I'm doing this via compilation.GetSymbolsWithName(typeName), but this method can return several matched symbols from different namespaces/assemblies.
So, the question: is there any way I can show this variants to user so he can decide the correct type?

For each diagnostic, you can add more than one fix.

Related

In an Intent Architect template, can I resolve a type (from a string) so it will include appropriate using statements?

In a template which generates code dynamically based on certain conditions, some of the code uses types which require additional using statements to compile correctly. How do I reference/use such a type such that the using will be included in the generated output iff that specific code is generated?
e.g. Given this code, how would I make sure the correct using is added?
if (attribute.IsEnum()) {
// Resolve the EnumToStringConverter type?
statements.Add($".HasConversion(new EnumToStringConverter<{attribute.Type.Element.Name}>());");
}
One way to do this is to use the UseType(...) method that is available on the CSharpTemplateBase base class (available in Intent.Modules.Common.CSharp.3.0.10 nuget package).
For example, you could try something like this:
if (attribute.IsEnum()) {
// Resolve the EnumToStringConverter type?
statements.Add($".HasConversion(new {UseType("EnumToStringConverter", "<your-required-namespace>"}<{attribute.Type.Element.Name}>());");
}
There is also another overload which would take in the fully qualified name. For example:
UseType("Microsoft.EntityFrameworkCore.Storage.ValueConversion.EnumToStringConverter")
(assuming you're using the EnumToStringConverter from EF Core)

How to best store commands and their response code for a .NET console app?

Description
My app takes user input (ReadLine()) and calls its corresponding function as a result.
At the moment, it's just a switch that checks for certain commands, with their response code inside cases, but I though I ought to separate them for cleaner code.
What's the design pattern of choice here?
Attempted Solution
I could make an abstract Command class with a commandName field and a mandatory Respond() function. Then, I'd hold a List of Commands, iterate over each to check if its commandName matches what the user input, and call its Respond() function (and break the loop) if so.
Problem
That still necessitates manually creating instances of each Command and adding them to the List that holds them.
If possible, I'd like for each Command to be automatically added. I wish to instruct the program to loop over every class in a Commands/ directory and instantiate and add it on its own, or something like that.
Can I do that? If not, what's the best alternative?
You have two solutions for what you are trying to achieve:
Reflection. You can use reflection to find all the classes that extend the abstraction of command.
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Then
// use activator to create an instance and add it to list
list.Add(Activator.CreateInstance(types[0])) // etc
Use dependency injection to create the list of types, by configuring a json or other configuration file.
This varies greatly, depending on the di framework of your choice.

FileHelpers - Creating a field object

I am trying to dynamically add field properties to a record class that I am also building dynamically using FileHelpers.Dynamic.DelimitedClassBuilder. I have no issues creating the class object and I currently add a field using the AddField(String) method.
As my apps grows I now have a need to declare specific field properties in various situations. So in the same sense I wanted to use FileHelpers.Dynamic.DelimitedFieldBuilder to create a field object and then pass that to my DelimitedClassBuilder object using the method AddField(DelimitedFieldBuilder).
However I am unable to instantiate a new object using FileHelpers.Dynamic.DelimitedFieldBuilder. When I issue the following code I get an error stating that DelimitedFieldBuilder does not contain a constructor that takes two arguments.
FileHelpers.Dynamic.DelimitedFieldBuilder fb = new FileHelpers.Dynamic.DelimitedFieldBuilder("ClassName", "Type");
Looking at the documentation it appears that this class does only have properties associated with it, so I am kind of stuck on how to actually implement this. It seems like it should be fairly easy but I cant seem to figure it out. Thanks for any help.
Not familiar with that functionality of file helpers; however, in the vast majority of functions/methods across .NET there is usually a way to assign properties after the class is instantiated.
Try something like this:
FileHelpers.Dynamic.DelimitedFieldBuilder fb = new FileHelpers.Dynamic.DelimitedFieldBuilder();
fb.Whatever = "ClassName";
fb.otherwhatever = "Type";
Just a stab. I have no idea if it will work or not.
The constructors of DelimitedFieldBuilder are internal so you'll run into difficulty with your approach. However AddField(String) returns a DelimitedFieldBuilder, so you might be able to use that.
It might be easier to make your own class MyFieldBuilder which calls the standard AddField(String).

Microsoft.Management.Infrastructure Namespace - Cim classes

I'm using new new Microsoft.Management.Infrastructure classes to handle WMI, but I've encountered a stumbling block, and can't find any information on how to work around this using these classes without having to fall back to using System.Management.ManagementObject.
Basically, Microsoft.Management.Infrastructure doesn't expose any methods for objects, which is what I'm having difficulties with.
I've retrieved a CimClass object, let's call it Win32_Process , called the property .CimClassProperties["Handle"] to get the Handle property and .Qualifiers to retrieve a list of qualifiers for the Handle property.
At this stage I'd like to delete one of the qualifiers, but there are no methods exposed that allow such a thing.
Using Microsoft.Management.ManagementObject namespace, I could get a ManagementClass object, again Win32_Process for the sake of the argument, call .Properties["Handle"].Qualifiers.Remove(<qualifierName>) to remove the qualifier, but no idea how to do this using the new classes and there's no info out there that I can find.
EDIT: I did some digging and found that to invoke methods on CIM objects you use the CimSession class, using either CimSession.InvokeMethod or CimSession.InvokeMethodAsync methods and was able to use it to invoke a method of a CimClass and of a CimInstance, but it does not appear to be able to invoke methods of any object outside of those two, from what I can see. Is this me?
I believe, it is not possible to modify the Qualifiers. Reason is it is read only property. Also, if you want something to do in code, they take the data in list or string array and manipulate them.
This is a very late answer, but I have found myself in a similar situation with trying to change Win32_TCPIPPrinterPort Printer IP Addresses and Names, which are also ReadOnly. I did come across some articles that refer to wbemtest.exe. This utility can be used to make changes like this, but use extreme caution as it is a WMI-Object editor and can break your system. This link will explain it better https://blogs.technet.microsoft.com/heyscriptingguy/2009/08/04/hey-scripting-guy-how-do-i-use-wmi-with-windows-powershell-to-return-information-about-properties/

Passing additional parameter not contained on DTO

I have a REST ServiceStack Route.Add declaration like this
Routes.Add<MyDTOObject>(/servicename/{property1fromDTO}); but I need to pass an additional String value that is not defined on MyDTOObject class declaration.
Is it possible to pass something like this Routes.Add<MyDTOObject>(/servicename/{property1fromDTO}/{additionalString}); and retrieve it on my OnGet(MyDTOObject request){...} method implementation?
Currently I'm only able to get values from request for attributes that are defined on the MyDTOObject class declaration as specified by the Annotation used for the Routes.Add.
On my Service code I have this:
public override object OnGet(MyDTOObject request){ ...
request.property1fromDTO //get value
...}
but I cannot do this:
request.additionalString //get the value
because Visual Studio doesn't recognizes it as a property of type MyDTOObject
Help will be appreciated since I'm fairly new to ServiceStack and RESTful services. Thanks!
Not exactly sure what you're trying to achieve but you can use a wildcard at the end to absorb multiple paths, e.g:
Routes.Add("/save/{Year}/{Week}/{DaysString*}");
Which will populate the known variables and leave the rest in DayString for you to parse manually. See this answer for more details.
You can ignore the additional path with the {ignore} keyword, e.g:
Routes.Add<MyDto>(/servicename/{property1fromDTO}/{ignore});
You also have full access to the request from inside a Service with base.Request, e.g:
base.Request.QueryString["param"];
base.Request.PathInfo
base.Request.RawUrl
*Note: it looks like you're using the old API (i.e. OnGet). I recommend inheriting from Service so you can use the New API as the Old API was removed in the next v4 of ServiceStack.*

Categories