Roslyn service is null - c#

What I am doing wrong here? The following code fails (and it's taken from Roslyn's source website)
public class CompletionServiceTests
{
public void AcquireCompletionService()
{
var workspace = new AdhocWorkspace();
var document = workspace
.AddProject("TestProject", LanguageNames.CSharp)
.AddDocument("TestDocument.cs", "");
var service = CompletionService.GetService(document);
Assert.NotNull(service);
}
}

I found the problem. I needed to do this instead:
var assemblies = new[]
{
Assembly.Load("Microsoft.CodeAnalysis"),
Assembly.Load("Microsoft.CodeAnalysis.CSharp"),
Assembly.Load("Microsoft.CodeAnalysis.Features"),
Assembly.Load("Microsoft.CodeAnalysis.CSharp.Features"),
};
var partTypes = MefHostServices.DefaultAssemblies.Concat(assemblies)
.Distinct()
.SelectMany(x => x.GetTypes())
.ToArray();
var compositionContext = new ContainerConfiguration()
.WithParts(partTypes)
.CreateContainer();
var host = MefHostServices.Create(compositionContext);
var workspace = new AdhocWorkspace(host);
var document = workspace
.AddProject("TestProject", LanguageNames.CSharp)
.AddDocument("TestDocument.cs", "");
var service = CompletionService.GetService(document);

Adding the Microsoft.CodeAnalysis.CSharp.Features NuGet package solved it for me.

Related

Amazon EventBridge rule cannot trigger a Lambda Function

Using the .Net AWSSDK.EventBridge I created a rule:
var client = new AmazonEventBridgeClient();
string ruleName = "SomeRule";
var putRuleRequest = new Amazon.EventBridge.Model.PutRuleRequest()
{
Name = ruleName,
ScheduleExpression = "rate(10 minutes)",
State = RuleState.ENABLED
}
await client.PutRuleAsync(putRuleRequest);
var target = new Amazon.EventBridge.Model.Target();
target.Arn = "ARN_LAMBDA_FUNCTION";
target.Id = "LAMBDA_FUNCTION_NAME";
target.Input = JsonSerializer.Serialize(new { someId, someDate});
var targetList = new List<Amazon.EventBridge.Model.Target>();
targetList.Add(target);
var putTargetRequest = new Amazon.EventBridge.Model.PutTargetsRequest()
{
Rule = ruleName,
Targets = targetList
};
await client.PutTargetsAsync(putTargetRequest);
The Lambda function is already created so I put the ARN and name on the Target. The idea is that there is one function but multiple rules will call it.
The rule, schedule, and target to the function are created when I run the code but the problem is that the function can't be triggered by the rule. When I edit the rule, update it in the AWS Console without changing anything the trigger works.
What am I missing?
After searching through I found out I was missing the permission for Lambda.
//This line replaces the code above
var putRuleResponse = client.PutRuleAsync(putRuleRequest).Result;
var lp = new Amazon.Lambda.Model.AddPermissionRequest();
lp.FunctionName = FUNCTION_ARN;
lp.Action = "lambda:InvokeFunction";
lp.SourceArn = putRuleResponse.RuleArn;
lp.Principal = "events.amazonaws.com";
lp.StatementId = "SomeStatement";
var lambdaClient = new AmazonLambdaClient();
await lambdaClient.AddPermissionAsync(lp);

How can I specify the editorconfig-derived OptionSet for an AdhocWorkspace in Roslyn?

Roslyn will let me add files to an AdhocWorkspace and run a formatter on them but I do not see how I can specify the formatting options. I want to derive them from a .editorconfig file passed in on the command line
var adhoc = new AdhocWorkspace();
var solutionInfo = SolutionInfo.Create(SolutionId.CreateNewId(),
VersionStamp.Default,
"MySolution");
adhoc.AddSolution(solutionInfo);
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(),
VersionStamp.Default,
"MyProject",
"MyProject.dll",
Microsoft.CodeAnalysis.LanguageNames.CSharp);
adhoc.AddProject(projectInfo);
foreach(var arg in args) {
var sourceText = SourceText.From(File.OpenText(arg).BaseStream);
adhoc.AddDocument(projectInfo.Id, arg, sourceText);
}
foreach(var document in adhoc.CurrentSolution.Projects.First().Documents){
var formattedDocument = Formatter.FormatAsync(document, adhoc.Options).Result;
var formattedText = formattedDocument.GetTextAsync().Result;
Console.WriteLine(formattedText);
}
adhoc.Options = adhoc.Options.WithChangedOption(...) will let me change a single option but I want the options to come from a .editorconfig file. Is there an API that will let me do this?
I found this project: https://github.com/dotnet/format
You can find the code here:
https://github.com/dotnet/format/blob/afc9284d4fb44cb695e17f10d2268944471a5c3b/src/Utilities/EditorConfigOptionsApplier.cs
I understood how it works and simplified it like this for parsing the .editorconfig:
public static OptionSet SimplifiedParsing(Workspace space)
{
OptionSet optionsSet = space.Options;
//reading .editorconfig
var editorConfigDictionary = File.ReadAllLines(#".editorconfig")
//here I take only the ones for csharp
.Where(x => x.StartsWith("csharp"))
.Select(x => x.Split(" = "))
.ToDictionary(x => x[0], y => y[1]);
var commonOptionsType = typeof(FormattingOptions);
var csharpOptionsType = typeof(CSharpFormattingOptions);
var formattingTypes = new[] {commonOptionsType, csharpOptionsType};
var optionType = typeof(IOption);
//here we are filtering all the methods from formattingTypes classes, with reflection, which parse the options by keys which are in editor config
var allParsingMethods = formattingTypes
.SelectMany(t => t.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty))
.Where(p => optionType.IsAssignableFrom(p.PropertyType))
.Select(p => (IOption) p.GetValue(null))
.Select(GetParsingMethod)
.Where(ows => ows.Item2 != null)
.ToImmutableArray();
foreach ((IOption, OptionStorageLocation, MethodInfo) parsingMethod in allParsingMethods)
{
//taking info for invoking TryGetOption
var (option, editorConfigStorage, tryGetOptionMethod) = parsingMethod;
object result = null;
//arguments for reflection invocation
var args = new[] {editorConfigDictionary, option.Type, result};
//editorConfigStorage instance on which to call the method
//invoking bool TryGetOption(IReadOnlyDictionary<string, string> rawOptions, Type type, out object result)
var isOptionPresent = (bool) tryGetOptionMethod.Invoke(editorConfigStorage, args);
result = args[2];
if (isOptionPresent)
{
var optionKey = new OptionKey(option, option.IsPerLanguage ? LanguageNames.CSharp : null);
//if option is parsed -> its present and we can add it to OptionSet
optionsSet = optionsSet.WithChangedOption(optionKey, result);
}
}
return optionsSet;
//helpers
(IOption, OptionStorageLocation, MethodInfo) GetParsingMethod(IOption option)
{
var editorConfigStorage = option.StorageLocations.IsDefaultOrEmpty
? null
: option.StorageLocations.FirstOrDefault(IsEditorConfigStorage);
//getting TryGetOption method of EditorConfigStorageLocation<T>
// original method signature:
// public bool TryGetOption(IReadOnlyDictionary<string, string> rawOptions, Type type, out object result)
var tryGetOptionMethod = editorConfigStorage?.GetType().GetMethod("TryGetOption");
return (option, editorConfigStorage, tryGetOptionMethod);
}
bool IsEditorConfigStorage(OptionStorageLocation storageLocation)
{
return storageLocation.GetType().FullName
.StartsWith("Microsoft.CodeAnalysis.Options.EditorConfigStorageLocation");
}
}

Create control flow graph for c# code using the .Net compiler Roslyn

I can't find a way to construct a control flow graph for c# code using Roslyn.
I know there is a namespace in the Roslyn compiler called "Microsoft.CodeAnalysis.FlowAnalysis" that contains some classes to create a control flow graph but I don't know how to use it.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.flowanalysis?view=roslyn-dotnet
there is a class called ControlFlowGraph.cs but the problem i can't create an object or a subclass from this class.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.flowanalysis.controlflowgraph?view=roslyn-dotnet
please if anyone knows how to use this namespace to construct a control flow graph or if there is an example to use.
thank you
I have manage to create the CFG from a method node:
CSharpParseOptions options = CSharpParseOptions.Default
.WithFeatures(new[] { new KeyValuePair<string, string>("flow-analysis", "")
});
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result; // path to your SLN file
ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph();
Dictionary<string, Stream> assemblies = new Dictionary<string, Stream>();
var projects = projectGraph.GetTopologicallySortedProjects().ToDictionary(
p => p,
p => solution.GetProject(p).Name);
var bllProjectId = projects.First(p => p.Value == "<your project name>").Key; // choose project for analysis
var projectId = bllProjectId;
solution = solution.WithProjectParseOptions(projectId, options);
Compilation compilation = solution.GetProject(projectId).GetCompilationAsync().Result;
if (compilation != null && !string.IsNullOrEmpty(compilation.AssemblyName))
{
var syntaxTree = compilation.SyntaxTrees.First();
// get syntax nodes for methods
var methodNodes = from methodDeclaration in syntaxTree.GetRoot().DescendantNodes()
.Where(x => x is MethodDeclarationSyntax)
select methodDeclaration;
foreach (MethodDeclarationSyntax node in methodNodes)
{
var model = compilation.GetSemanticModel(node.SyntaxTree);
node.Identifier.ToString().Dump();
if (node.SyntaxTree.Options.Features.Any())
{
var graph = ControlFlowGraph.Create(node, model); // CFG is here
}
else
{
// "No features".Dump();
}
}
}
The next step will be anaylysis of the CFG ...
Karel
Depending on the Karel's answer and comment this is how to create a Control Flow Graph without errors:
var source = #"
class C
{
int M(int x)
{
x = 0;
int y = x * 3;
return y;
}
}";
CSharpParseOptions options = CSharpParseOptions.Default
.WithFeatures(new[] { new KeyValuePair<string, string>("flow-analysis", "")});
var tree = CSharpSyntaxTree.ParseText(source, options);
var compilation = CSharpCompilation.Create("c", new[] { tree });
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var methodBodySyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<BaseMethodDeclarationSyntax>().Last();
var cfgFromSyntax = ControlFlowGraph.Create(methodBodySyntax, model);

Get current iteration from TFS

I need to get current iteration's path from TFS project. I'm able to use REST API query <server>/<project>/_apis/work/teamsettings/iterations?$timeframe=current&api-version=v2.0-preview but I don't want to perform query and parse JSON response. I want to use appropriate API in .NET client libraries for VSTS (and TFS).
I have an instance of the VssConnection. How can I get the path of current iteration from this object?
You can get the current iteration using the WorkHttpClient without having to iterate:
var creds = new VssBasicCredential(string.Empty, "personalaccesstoken");
VssConnection connection = new VssConnection(new Uri("url"), creds);
var workClient = connection.GetClient<WorkHttpClient>();
var teamContext = new TeamContext(teamId);
teamContext.ProjectId = projectId;
var currentIteration = await workClient.GetTeamIterationsAsync(teamContext, "current");
The simplest way I've found to do it was by using ICommonStructureService4 and TeamSettingsConfigurationService methods:
static TfsTeamProjectCollection _tfs = TfsTeamProjectCollectionFactory
.GetTeamProjectCollection("<tfsUri>")
(...)
static string GetCurrentIterationPath()
{
var css = _tfs.GetService<ICommonStructureService4>();
var teamProjectName = "<teamProjectName>";
var project = css.GetProjectFromName(teamProjectName);
var teamName = "<teamName>";
var teamSettingsStore =
_tfs.GetService<TeamSettingsConfigurationService>();
var settings = teamSettingsStore
.GetTeamConfigurationsForUser(new[] { project.Uri })
.Where(c => c.TeamName == teamName)
.FirstOrDefault();
if (settings == null)
{
var currentUser = System.Threading.Thread.CurrentPrincipal.Identity.Name;
throw new InvalidOperationException(
$"User '{currentUser}' doesn't have access to '{teamName}' team project.");
}
return settings.TeamSettings.CurrentIterationPath;
}
And returning the TeamSettings.CurrentIterationPath property.
I found a solution using VssConnection:
var workClient = connection.GetClient<WorkHttpClient>();
var iterations = workClient.GetTeamIterationsAsync(new TeamContext("project-name")).Result;
var currentDate = DateTime.Now.Date;
var currentIterationPath = iterations
.Select(i => new { i.Path, i.Attributes })
.FirstOrDefault(i => currentDate >= i.Attributes.StartDate &&
currentDate <= i.Attributes.FinishDate)
?.Path;
Here is a case provides a solution: Get the current iteration path from TFS
private static XmlNode currentIterationNode;
TfsTeamProjectCollection tpc = TFSConncetion(#"http://tfs/url");
ICommonStructureService4 css = tpc.GetService<ICommonStructureService4>();;
WorkItemStore workItemStore = new WorkItemStore(tpc);
foreach (Project teamProject in workItemStore.Projects)
{
if (teamProject.Name.Equals("TeamProjectNameGoesHere"))
{
NodeInfo[] structures = css.ListStructures(teamProject.Uri.ToString());
NodeInfo iterations = structures.FirstOrDefault(n => n.StructureType.Equals("ProjectLifecycle"));
if (iterations != null)
{
XmlElement iterationsTree = css.GetNodesXml(new[] { iterations.Uri }, true);
XmlNodeList nodeList = iterationsTree.ChildNodes;
currentIterationNode = FindCurrentIteration(nodeList);
String currentIterationPath = currentIterationNode.Attributes["Path"].Value;
}
}
}

ElasticSearch NEST Delete all document

I am using ElastciSearch 2.3.0
I am trying to delete documents from the ElasticSearch using .net and NEST for specific index.
I only want to delete all documents and not the _mapping
DeleteByQueryRequest r = new DeleteByQueryRequest(new IndexName() { Name = indexName });
r.QueryOnQueryString = "*";
var response = client.DeleteByQuery(r);
I am try to do this by using above code but it is not working.
Please suggest on what's wrong with the above code or how this can be done.
Thanks for your help in advance.
Don't use delete by query it was made a plugin since elastic 2.0 for a good reason. You can get out of memory exceptions easy.
You should delete the whole index and recreate the mappings
static void Main(string[] args)
{
ElasticClient db = new ElasticClient(new Uri("http://localhost.fiddler:9200"));
db.IndexMany(Enumerable.Range(0, 100).Select(i => new Data { Id = i, Name = "Name" + i }), "test_index");
var mappings = db.GetMapping<Data>();
var delete = db.DeleteIndex(new DeleteIndexRequest("test_index"));
var indexMapping = mappings.IndexTypeMappings["test_index"].ToDictionary(k => k.Key, v => (ITypeMapping)v.Value);
db.CreateIndex(new CreateIndexRequest("test_index")
{
Mappings = new Mappings(indexMapping)
});
Console.ReadLine();
}
class Data
{
public int Id { get; set; }
public string Name { get; set; }
}
Raw copy of index
var res = db.LowLevel.IndicesGetMapping<JObject>("test_index");
var delete = db.DeleteIndex(new DeleteIndexRequest("test_index"));
var mappings = res.Body["test_index"].ToString();
var create = db.LowLevel.IndicesCreate<JObject>("test_index", mappings);
If you really need to install the plug-in
sudo bin/plugin install delete-by-query
It worked.
Thanks a lot.
var res = db.LowLevel.IndicesGetMapping<JObject>("test_index");
var delete = db.DeleteIndex(new DeleteIndexRequest("test_index"));
var mappings = res.Body["test_index"].ToString();
var create = db.LowLevel.IndicesCreate<JObject>("test_index", mappings);

Categories