Roslyn DiagnosticAnalyzer With Document Access - c#

I've written a diagnostic analyzer to check if Const names have been created in a resx file in the solution and localize them to use the resx file. I need to gain access to the Document/Solution my field declaration has been registered in
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeConstDeclaration, SyntaxKind.FieldDeclaration);
}
public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
{
var semantic = (FieldDeclarationSyntax)context.Node;
}
I don't see a way to get the Document/Solution in the AnalysisContext
Nor do I see a way to get it from the SyntaxNodeAnalysisContext or the Semantic Model.
How can I get the Solution or Document in the Diagnostic Analyzer?
Edit
I tried getting the solution through the AdhocWorkspace however the current projects are not populated so that will not work.
var solution = new AdhocWorkspace().CurrentSolution;

Related

Does webview2 in winui3 not support changing the download location?

I used cefsharp, I need to generate folders according to certain rules and download the web content to the specified directory. I'm going to replace it with webview2. I find that there is no way to specify the default download directory. Do you have any way?
It may evolve in the future, but currently, you must define the WEBVIEW2_USER_DATA_FOLDER environment variable manually as explained here WebView2 Globals, something like this:
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", #"c:\temp\mydata");
MyWebView.CoreWebView2Initialized += MyWebView_CoreWebView2Initialized;
}
private void MyWebView_CoreWebView2Initialized(WebView2 sender, CoreWebView2InitializedEventArgs args)
{
// udf will contain c:\temp\mydata
var udf = sender.CoreWebView2.Environment.UserDataFolder;
}
...
}

c# Local Application edit app without recompiling/reinstallation [duplicate]

I would like to store an API key in a configuration file without checking it into source control, and read the data in my UWP app.
A common solution is to store the key in .config file (such as app.config or web.config) and access it like so:
var apiKey = ConfigurationManager.AppSettings.Get("apiKey");
I'm working on a Universal Windows (UWP) app and can't access the System.Configuration namespace that holds ConfigurationManager.
How can I access AppSettings in UWP app?
Alternatively, what's the best way to access configuration data in an UWP app?
In my specific use case I needed to use an external file that is not tracked by source control. There are two ways to access data from resource or configuration files.
One is to open and parse a configuration file. Given a file sample.txt with Build Action Content (Copy to Output Directory doesn't matter), we can read it with
var uri = new System.Uri("ms-appx:///sample.txt");
var sampleFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
or
var packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var sampleFile = await packageFolder.GetFileAsync("sample.txt");
followed by
var contents = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
Alternatively, we can use Resources. Add a new Resource item to the project, called resourcesFile.resw. To access data, use:
var resources = new Windows.ApplicationModel.Resources.ResourceLoader("resourcesFile");
var token = resources.GetString("secret");
I wrote more verbose answer in a blog post Custom resource files in UWP
It's an old question, but here my solution :
Create a partial class Config.cs (for example) with all the properties you'r needed
Add a partial method void Init()
Call Init in the constructor
Create an other file Config.partial.cs with the void Init() method filling all your properties
-> Use #if DEBUG / #else / #endif to switch from Debug/Release
-> Use exclude Config.partial.cs from Github to not import it in the repository
Now it compile and it's not in the repository
Alternatively you can set in Config.cs default (not secret) datas.
Config.cs :
public partial class Config
{
public Config()
{
Init();
}
partial void Init();
public string ApiKey{ get; private set; }= "DefaultValueAPIKEY";
}
Config.partial.cs
public partial class Config
{
partial void Init()
{
#if DEBUG
this.ApiKey = "DebugAPIKEY";
#else
this.ApiKey = "ReleaseAPIKEY";
#endif
}
}
I'm thinking that what you call "ApiKey" is the static key that an API gives you to generate an access token. If this is the case, maybe the best way to achieve this is to create a static class out of the source control with that value inside of it, something like this:
public static class MyCredentials
{
public static string MyApiKey = "apiKey";
}
Then you access that value easily from your code:
var myApiKey = MyCredentials.MyApiKey;
If you want to store values in a plain-text file instead you will have to write/read it manually using StorageFile and FileIO classes.
Instead, if "ApiKey" means the dynamic access token, then the best solution is use ApplicationDataContainer as stratever says.
You don't need to create a configuration file. UWP has a built-in solution to store local settings/configurations. Please check this tutorial:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299098.aspx
Using ApplicationDataContainer, you will be able to get a value by key:
Object value = localSettings.Values["exampleSetting"];

ConfigurationManager and AppSettings in universal (UWP) app

I would like to store an API key in a configuration file without checking it into source control, and read the data in my UWP app.
A common solution is to store the key in .config file (such as app.config or web.config) and access it like so:
var apiKey = ConfigurationManager.AppSettings.Get("apiKey");
I'm working on a Universal Windows (UWP) app and can't access the System.Configuration namespace that holds ConfigurationManager.
How can I access AppSettings in UWP app?
Alternatively, what's the best way to access configuration data in an UWP app?
In my specific use case I needed to use an external file that is not tracked by source control. There are two ways to access data from resource or configuration files.
One is to open and parse a configuration file. Given a file sample.txt with Build Action Content (Copy to Output Directory doesn't matter), we can read it with
var uri = new System.Uri("ms-appx:///sample.txt");
var sampleFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
or
var packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var sampleFile = await packageFolder.GetFileAsync("sample.txt");
followed by
var contents = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
Alternatively, we can use Resources. Add a new Resource item to the project, called resourcesFile.resw. To access data, use:
var resources = new Windows.ApplicationModel.Resources.ResourceLoader("resourcesFile");
var token = resources.GetString("secret");
I wrote more verbose answer in a blog post Custom resource files in UWP
It's an old question, but here my solution :
Create a partial class Config.cs (for example) with all the properties you'r needed
Add a partial method void Init()
Call Init in the constructor
Create an other file Config.partial.cs with the void Init() method filling all your properties
-> Use #if DEBUG / #else / #endif to switch from Debug/Release
-> Use exclude Config.partial.cs from Github to not import it in the repository
Now it compile and it's not in the repository
Alternatively you can set in Config.cs default (not secret) datas.
Config.cs :
public partial class Config
{
public Config()
{
Init();
}
partial void Init();
public string ApiKey{ get; private set; }= "DefaultValueAPIKEY";
}
Config.partial.cs
public partial class Config
{
partial void Init()
{
#if DEBUG
this.ApiKey = "DebugAPIKEY";
#else
this.ApiKey = "ReleaseAPIKEY";
#endif
}
}
I'm thinking that what you call "ApiKey" is the static key that an API gives you to generate an access token. If this is the case, maybe the best way to achieve this is to create a static class out of the source control with that value inside of it, something like this:
public static class MyCredentials
{
public static string MyApiKey = "apiKey";
}
Then you access that value easily from your code:
var myApiKey = MyCredentials.MyApiKey;
If you want to store values in a plain-text file instead you will have to write/read it manually using StorageFile and FileIO classes.
Instead, if "ApiKey" means the dynamic access token, then the best solution is use ApplicationDataContainer as stratever says.
You don't need to create a configuration file. UWP has a built-in solution to store local settings/configurations. Please check this tutorial:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299098.aspx
Using ApplicationDataContainer, you will be able to get a value by key:
Object value = localSettings.Values["exampleSetting"];

Winform app: Compiled App.Config-like file?

I would like to know if there is some kind of built-in compiled "App.Config" file?
The goal is to be able to have one of our library which can have some of its default values overriden when being used in some client application.
Thoses DLL are loaded dynamically, so I cannot just give a parameter in the constructor.
I don't want to use the App.config file because the user can edit those values(otherwise it would have been just fine).
There are several different ways to solve this.
If you like the idea of config-files, but do not want to have it accessible by end users in the compiled application, perhaps you can create your own settings-file in a format that suits your needs, and include it as an embedded resource?
An upside of this would be that you can access it as a regular XML or config file or whatever in Visual Studio, while it will be hidden from the end user. Personally I think I would prefer this to using special code / classes to store config-data.
To include a file as an embedded resource, include it into one of your Visual Studio projects, right click the included file and select Properties. Now under Build Action, select Embedded Resource. When you build your project now, the file will be included internally in the produced .dll-file.
I'm sure you'll be able to find lot's of info about how to access an embedded resource from code. As an example, there are some useful examples in this SO question. Note especially this answer, which also mentions an alternative way to include a resource.
Expanding on my comment... you could just make an interface for a settings class with hardcoded values, and then make different implementations of that interface. To actually change which one to use, all you'd need to do is comment/uncomment the line that instantiates an object into your settings variable before you build the dll:
public class MainDllProject
{
ISettings m_Settings;
public MainDllProject()
{
// Change this before compiling
this.m_Settings = new DebugSettings();
//this.m_Settings = new DeploySettings();
// use settings from the settings class
String setting1 = this.m_Settings.Setting1
Int32 setting2 = this.m_Settings.Setting2
//...
}
}
public interface ISettings
{
String Setting1 { get; }
Int32 Setting2 { get; }
}
public class DebugSettings: ISettings
{
public String Setting1
{ get { return "data_debug";} }
public Int32 Setting2
{ get { return 2;} }
}
public class DeploySettings: ISettings
{
public String Setting1
{ get { return "data_deploy";} }
public Int32 Setting2
{ get { return 1;} }
}
On finding "a built-in way of solving this", as you said, maybe this will be useful for you...
You can actually use the Visual Studio build configuration manager to build with different settings. Using the #If directives, you can automatically make it select which lines of code to use based on the configuration. A simple example based on the default debug configuration, which adds the "DEBUG=True" variable automatically:
public MainDllProject()
{
#If DEBUG Then
this.m_Settings = new DebugSettings();
#ElseIf
this.m_Settings = new DeploySettings();
#End if
}
You can actually make your own custom-named variables to check on just like that DEBUG one: after making a configuration, open the Project properties window, go to the Compile tab, select that specific configuration in the dropdown, and then at the bottom select "Advanced Compile Options". In there is a line "Custom constants" in which you can add such variables. For simple if-statements, you can just make a boolean like "CLIENTDEPLOY=True", and then you can use #If CLIENTDEPLOY Then in your code.

ReportDiagnostic on Partial Classes

I am modifying the default analyzer project that comes from the code analyzer template to try and get it to report at all of the declarations for a partial class.
I have modified the code to:
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
// Find just those named type symbols with names containing lowercase letters.
if (namedTypeSymbol.Name.ToCharArray().Any(char.IsLower))
{
foreach (var location in namedTypeSymbol.Locations)
{
// For all such symbols, produce a diagnostic.
var diagnostic = Diagnostic.Create(Rule, location, namedTypeSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
In two separate files, I have partial classes like this:
// File1.cs
partial class Foo
{
public string BarString;
}
// File2.cs
partial class Foo
{
public string FooBarString;
}
I put breakpoints on the ReportDiagnostic and am seeing it called for each location, but within Visual Studio it only reports diagnostics within a single file.
If I put multiple implementations of Foo in a single file (and it happens to be reporting on that files declaration) then I will see both diagnostics reported.
Am I misunderstanding how diagnostics are supposed to be reported or is this a bug? If it is a bug, is it a Roslyn problem or is it a problem with Visual Studio's consumption of Roslyn?
This is a limitation of the V1 implementation of the Visual Studio diagnostic service.
There is an issue in the Roslyn repository to track this issue:
https://github.com/dotnet/roslyn/issues/3748#issuecomment-117231706
From the response in the Github issue:
This is a known issue in the v1 implementation of the Visual Studio
IDE's diagnostic service. It currently doesn't handle analyzer
reporting diagnostics outside the document being analyzed. So, if
File1.cs has the primary definition of Foo for which AnalyzeSymbol was
invoked, then the diagnostic service only retains diagnostics reported
by the analyzer within this file.

Categories

Resources