Skip to content

Commit 7c7c64d

Browse files
matherm-aboehmunchase
authored andcommitted
fix: Fix some analyzer warnings
Most VSTHRD010 warnings are fixed by implementing the method with async/await and awaiting for ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(). This requires to implement async factory pattern for constructors. Actually use the base class implementation of BaseCodeGenDescriptor.
1 parent 0648740 commit 7c7c64d

13 files changed

Lines changed: 214 additions & 140 deletions

src/Unchase.OpenAPI.Connectedservice.Shared/CodeGeneration/BaseCodeGenDescriptor.cs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88

99
using System;
1010
using System.IO;
11+
using System.Reflection;
1112
using System.Threading.Tasks;
1213

1314
using EnvDTE;
1415
using Microsoft.VisualStudio.ComponentModelHost;
1516
using Microsoft.VisualStudio.ConnectedServices;
17+
using Microsoft.VisualStudio.Shell;
1618
using NuGet.VisualStudio;
1719
using Unchase.OpenAPI.ConnectedService.Common;
20+
using Task = System.Threading.Tasks.Task;
1821

1922
namespace Unchase.OpenAPI.ConnectedService.CodeGeneration
2023
{
@@ -28,9 +31,9 @@ internal abstract class BaseCodeGenDescriptor
2831

2932
public ConnectedServiceHandlerContext Context { get; }
3033

31-
public Project Project { get; }
34+
public Project Project { get; private set; }
3235

33-
public string ServiceUri { get; }
36+
public string ServiceUri { get; private set; }
3437

3538
public Instance Instance { get; }
3639

@@ -40,36 +43,49 @@ internal abstract class BaseCodeGenDescriptor
4043

4144
protected BaseCodeGenDescriptor(ConnectedServiceHandlerContext context, Instance serviceInstance)
4245
{
43-
Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
44-
InitNuGetInstaller();
45-
4646
Instance = serviceInstance;
47+
Context = context;
48+
}
49+
50+
protected virtual async Task InitializeAsync()
51+
{
52+
await InitNuGetInstallerAsync();
53+
54+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
55+
Project = Context.ProjectHierarchy?.GetProject();
4756

48-
if (serviceInstance.ServiceConfig.UseRelativePath)
57+
var serviceConfig = Instance.ServiceConfig;
58+
if (serviceConfig.UseRelativePath)
4959
{
50-
var projectPath = context.ProjectHierarchy?.GetProject().Properties.Item("FullPath").Value.ToString();
51-
if (projectPath == null || !File.Exists(Path.Combine(projectPath, serviceInstance.ServiceConfig.Endpoint)))
60+
var projectPath = Project?.Properties.Item("FullPath").Value.ToString();
61+
if (projectPath == null || !File.Exists(Path.Combine(projectPath, serviceConfig.Endpoint)))
5262
{
5363
throw new ArgumentException("Please input the service endpoint with exists file path.", "Service Endpoint");
5464
}
5565

56-
ServiceUri = Path.Combine(projectPath, serviceInstance.ServiceConfig.Endpoint);
66+
ServiceUri = Path.Combine(projectPath, serviceConfig.Endpoint);
5767
}
5868
else
5969
{
60-
ServiceUri = serviceInstance.ServiceConfig.Endpoint;
70+
ServiceUri = serviceConfig.Endpoint;
6171
}
62-
63-
Context = context;
64-
Project = context.ProjectHierarchy.GetProject();
6572
}
66-
private void InitNuGetInstaller()
73+
74+
private async Task InitNuGetInstallerAsync()
6775
{
68-
var componentModel = (IComponentModel)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SComponentModel));
76+
var componentModel = await ServiceProvider.GetGlobalServiceAsync<SComponentModel, IComponentModel>();
77+
//TODO: use new interfaces?
6978
PackageInstallerServices = componentModel.GetService<IVsPackageInstallerServices>();
7079
PackageInstaller = componentModel.GetService<IVsPackageInstaller>();
7180
}
7281

82+
public static async Task<T> CreateAsync<T>(ConnectedServiceHandlerContext context, Instance serviceInstance) where T : BaseCodeGenDescriptor
83+
{
84+
var instance = (T)Activator.CreateInstance(typeof(T), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[] { context, serviceInstance }, null, null);
85+
await instance.InitializeAsync();
86+
return instance;
87+
}
88+
7389
#endregion
7490

7591
#region Methods
@@ -80,10 +96,11 @@ private void InitNuGetInstaller()
8096

8197
public abstract Task<string> AddGeneratedNSwagFileAsync();
8298

83-
protected string GetReferenceFileFolder()
99+
protected async Task<string> GetReferenceFileFolderAsync()
84100
{
85101
var serviceReferenceFolderName = Context.HandlerHelper.GetServiceArtifactsRootFolder();
86-
return Path.Combine(Project.GetServiceFolderPath(serviceReferenceFolderName, Context.ServiceInstance.Name));
102+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
103+
return Project.GetServiceFolderPath(serviceReferenceFolderName, Instance.Name);
87104
}
88105

89106
#endregion

src/Unchase.OpenAPI.Connectedservice.Shared/CodeGeneration/NSwagCodeGenDescriptor.cs

Lines changed: 54 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using NSwag.Commands.Generation;
2020
using Unchase.OpenAPI.ConnectedService.Common;
2121
using Unchase.OpenAPI.ConnectedService.Views;
22+
using Task = System.Threading.Tasks.Task;
2223

2324
namespace Unchase.OpenAPI.ConnectedService.CodeGeneration
2425
{
@@ -27,7 +28,7 @@ internal class NSwagCodeGenDescriptor :
2728
{
2829
#region Constructors
2930

30-
public NSwagCodeGenDescriptor(ConnectedServiceHandlerContext context, Instance serviceInstance)
31+
private NSwagCodeGenDescriptor(ConnectedServiceHandlerContext context, Instance serviceInstance)
3132
: base(context, serviceInstance) { }
3233

3334
#endregion
@@ -141,7 +142,7 @@ public override async Task<string> AddGeneratedCodeAsync()
141142
await Context.Logger.WriteMessageAsync(LoggerMessageCategory.Information, "Generating Client Proxy for OpenAPI (Swagger) Client...");
142143
try
143144
{
144-
var result = await GenerateCodeAsync(Context, Instance);
145+
var result = await GenerateCodeAsync();
145146
await Context.Logger.WriteMessageAsync(LoggerMessageCategory.Information, "Client Proxy for OpenAPI (Swagger) Client was generated.");
146147
return result;
147148
}
@@ -157,7 +158,7 @@ public override async Task<string> AddGeneratedNSwagFileAsync()
157158
await Context.Logger.WriteMessageAsync(LoggerMessageCategory.Information, "Generating NSwag-file for OpenAPI (Swagger)...");
158159
try
159160
{
160-
var result = await GenerateNSwagFileAsync(Context, Instance);
161+
var result = await GenerateNSwagFileAsync();
161162
await Context.Logger.WriteMessageAsync(LoggerMessageCategory.Information, $"NSwag-file \"{Path.GetFileName(result)}\" for OpenAPI (Swagger) was generated.");
162163
return result;
163164
}
@@ -168,15 +169,14 @@ public override async Task<string> AddGeneratedNSwagFileAsync()
168169
}
169170
}
170171

171-
internal async Task<string> GenerateCodeAsync(ConnectedServiceHandlerContext context, Instance instance)
172+
internal async Task<string> GenerateCodeAsync()
172173
{
173-
var serviceFolder = instance.Name;
174-
var rootFolder = context.HandlerHelper.GetServiceArtifactsRootFolder();
175-
var folderPath = context.ProjectHierarchy.GetProject().GetServiceFolderPath(rootFolder, serviceFolder);
174+
var folderPath = await GetReferenceFileFolderAsync();
176175

177-
var nSwagFilePath = Path.Combine(folderPath, $"{instance.ServiceConfig.GeneratedFileName}.nswag");
178-
var document = await NSwagDocument.LoadWithTransformationsAsync(nSwagFilePath, instance.ServiceConfig.Variables);
179-
document.Runtime = instance.ServiceConfig.Runtime;
176+
var serviceConfig = Instance.ServiceConfig;
177+
var nSwagFilePath = Path.Combine(folderPath, $"{serviceConfig.GeneratedFileName}.nswag");
178+
var document = await NSwagDocument.LoadWithTransformationsAsync(nSwagFilePath, serviceConfig.Variables);
179+
document.Runtime = serviceConfig.Runtime;
180180

181181
var nSwagJsonTempFileName = Path.GetTempFileName();
182182
var csharpClientTempFileName = Path.GetTempFileName();
@@ -207,10 +207,10 @@ internal async Task<string> GenerateCodeAsync(ConnectedServiceHandlerContext con
207207

208208
await document.ExecuteAsync();
209209

210-
nSwagJsonOutputPath = await context.HandlerHelper.AddFileAsync(nSwagJsonTempFileName, nSwagJsonOutputPath, new AddFileOptions { OpenOnComplete = instance.ServiceConfig.OpenGeneratedFilesOnComplete });
210+
nSwagJsonOutputPath = await Context.HandlerHelper.AddFileAsync(nSwagJsonTempFileName, nSwagJsonOutputPath, new AddFileOptions { OpenOnComplete = serviceConfig.OpenGeneratedFilesOnComplete });
211211
if (document.CodeGenerators?.OpenApiToCSharpClientCommand != null)
212212
{
213-
if (instance.ServiceConfig.ExcludeTypeNamesLater)
213+
if (serviceConfig.ExcludeTypeNamesLater)
214214
{
215215
var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(File.ReadAllText(csharpClientTempFileName), CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest));
216216
var root = await parsedSyntaxTree.GetRootAsync();
@@ -233,19 +233,19 @@ internal async Task<string> GenerateCodeAsync(ConnectedServiceHandlerContext con
233233
}
234234
}
235235

236-
await context.HandlerHelper.AddFileAsync(csharpClientTempFileName, csharpClientOutputPath,
237-
new AddFileOptions { OpenOnComplete = instance.ServiceConfig.OpenGeneratedFilesOnComplete });
236+
await Context.HandlerHelper.AddFileAsync(csharpClientTempFileName, csharpClientOutputPath,
237+
new AddFileOptions { OpenOnComplete = serviceConfig.OpenGeneratedFilesOnComplete });
238238
}
239239
if (document.CodeGenerators?.OpenApiToTypeScriptClientCommand != null)
240240
{
241-
await context.HandlerHelper.AddFileAsync(typeScriptClientTempFileName, typeScriptClientOutputPath,
242-
new AddFileOptions { OpenOnComplete = instance.ServiceConfig.OpenGeneratedFilesOnComplete });
241+
await Context.HandlerHelper.AddFileAsync(typeScriptClientTempFileName, typeScriptClientOutputPath,
242+
new AddFileOptions { OpenOnComplete = serviceConfig.OpenGeneratedFilesOnComplete });
243243
}
244244

245245
if (document.CodeGenerators?.OpenApiToCSharpControllerCommand != null)
246246
{
247-
await context.HandlerHelper.AddFileAsync(controllerTempFileName, controllerOutputPath,
248-
new AddFileOptions { OpenOnComplete = instance.ServiceConfig.OpenGeneratedFilesOnComplete });
247+
await Context.HandlerHelper.AddFileAsync(controllerTempFileName, controllerOutputPath,
248+
new AddFileOptions { OpenOnComplete = serviceConfig.OpenGeneratedFilesOnComplete });
249249
}
250250
}
251251
catch (Exception ex)
@@ -278,103 +278,87 @@ await context.HandlerHelper.AddFileAsync(controllerTempFileName, controllerOutpu
278278
return nSwagJsonOutputPath;
279279
}
280280

281-
internal async Task<string> GenerateNSwagFileAsync(ConnectedServiceHandlerContext context, Instance instance)
281+
internal async Task<string> GenerateNSwagFileAsync()
282282
{
283283
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
284-
var nameSpace = context.ProjectHierarchy.GetProject().GetNameSpace();
284+
var nameSpace = Project.GetNameSpace();
285285

286-
string serviceUrl;
287-
if (instance.ServiceConfig.UseRelativePath)
288-
{
289-
var projectPath = context.ProjectHierarchy?.GetProject().Properties.Item("FullPath").Value.ToString();
290-
if (projectPath == null || !File.Exists(Path.Combine(projectPath, instance.ServiceConfig.Endpoint)))
291-
{
292-
throw new ArgumentException("Please input the service endpoint with exists file path.", "Service Endpoint");
293-
}
294-
295-
serviceUrl = Path.Combine(projectPath, instance.ServiceConfig.Endpoint);
296-
}
297-
else
298-
{
299-
serviceUrl = instance.ServiceConfig.Endpoint;
300-
}
286+
var serviceConfig = Instance.ServiceConfig;
301287

302-
if (string.IsNullOrWhiteSpace(instance.Name))
288+
if (string.IsNullOrWhiteSpace(Instance.Name))
303289
{
304-
instance.Name = Constants.DefaultServiceName;
290+
Instance.Name = Constants.DefaultServiceName;
305291
}
306292

307-
var rootFolder = context.HandlerHelper.GetServiceArtifactsRootFolder();
308-
var serviceFolder = instance.Name;
293+
var rootFolder = Context.HandlerHelper.GetServiceArtifactsRootFolder();
294+
var serviceFolder = Instance.Name;
309295
var document = NSwagDocument.Create();
310-
if (instance.ServiceConfig.GenerateCSharpClient)
296+
if (serviceConfig.GenerateCSharpClient)
311297
{
312-
instance.ServiceConfig.OpenApiToCSharpClientCommand.OutputFilePath = $"{instance.ServiceConfig.GeneratedFileName}.cs";
313-
if (string.IsNullOrWhiteSpace(instance.ServiceConfig.OpenApiToCSharpClientCommand.Namespace))
298+
serviceConfig.OpenApiToCSharpClientCommand.OutputFilePath = $"{serviceConfig.GeneratedFileName}.cs";
299+
if (string.IsNullOrWhiteSpace(serviceConfig.OpenApiToCSharpClientCommand.Namespace))
314300
{
315-
instance.ServiceConfig.OpenApiToCSharpClientCommand.Namespace = $"{nameSpace}.{serviceFolder}";
301+
serviceConfig.OpenApiToCSharpClientCommand.Namespace = $"{nameSpace}.{serviceFolder}";
316302
}
317303

318-
document.CodeGenerators.OpenApiToCSharpClientCommand = instance.ServiceConfig.OpenApiToCSharpClientCommand;
304+
document.CodeGenerators.OpenApiToCSharpClientCommand = serviceConfig.OpenApiToCSharpClientCommand;
319305
}
320306

321-
if (instance.ServiceConfig.GenerateTypeScriptClient)
307+
if (serviceConfig.GenerateTypeScriptClient)
322308
{
323-
instance.ServiceConfig.OpenApiToTypeScriptClientCommand.OutputFilePath = $"{instance.ServiceConfig.GeneratedFileName}.ts";
324-
document.CodeGenerators.OpenApiToTypeScriptClientCommand = instance.ServiceConfig.OpenApiToTypeScriptClientCommand;
309+
serviceConfig.OpenApiToTypeScriptClientCommand.OutputFilePath = $"{serviceConfig.GeneratedFileName}.ts";
310+
document.CodeGenerators.OpenApiToTypeScriptClientCommand = serviceConfig.OpenApiToTypeScriptClientCommand;
325311
}
326312

327-
if (instance.ServiceConfig.GenerateCSharpController)
313+
if (serviceConfig.GenerateCSharpController)
328314
{
329-
instance.ServiceConfig.OpenApiToCSharpControllerCommand.OutputFilePath =
330-
instance.ServiceConfig.GenerateCSharpClient
331-
? $"{instance.ServiceConfig.GeneratedFileName}Controller.cs"
332-
: $"{instance.ServiceConfig.GeneratedFileName}.cs";
315+
serviceConfig.OpenApiToCSharpControllerCommand.OutputFilePath =
316+
serviceConfig.GenerateCSharpClient
317+
? $"{serviceConfig.GeneratedFileName}Controller.cs"
318+
: $"{serviceConfig.GeneratedFileName}.cs";
333319

334-
if (string.IsNullOrWhiteSpace(instance.ServiceConfig.OpenApiToCSharpControllerCommand.Namespace))
320+
if (string.IsNullOrWhiteSpace(serviceConfig.OpenApiToCSharpControllerCommand.Namespace))
335321
{
336-
instance.ServiceConfig.OpenApiToCSharpControllerCommand.Namespace = $"{nameSpace}.{serviceFolder}";
322+
serviceConfig.OpenApiToCSharpControllerCommand.Namespace = $"{nameSpace}.{serviceFolder}";
337323
}
338324

339-
document.CodeGenerators.OpenApiToCSharpControllerCommand = instance.ServiceConfig.OpenApiToCSharpControllerCommand;
325+
document.CodeGenerators.OpenApiToCSharpControllerCommand = serviceConfig.OpenApiToCSharpControllerCommand;
340326
}
341327

342328
document.SelectedSwaggerGenerator = new FromDocumentCommand
343329
{
344-
OutputFilePath = $"{instance.ServiceConfig.GeneratedFileName}.nswag.json",
345-
Url = instance.ServiceConfig.ConvertFromOdata ? null : serviceUrl,
346-
Json = instance.ServiceConfig.CopySpecification || instance.ServiceConfig.ConvertFromOdata
347-
? File.ReadAllText(instance.SpecificationTempPath)
330+
OutputFilePath = $"{serviceConfig.GeneratedFileName}.nswag.json",
331+
Url = serviceConfig.ConvertFromOdata ? null : ServiceUri,
332+
Json = serviceConfig.CopySpecification || serviceConfig.ConvertFromOdata
333+
? File.ReadAllText(Instance.SpecificationTempPath)
348334
: null
349335
};
350336

351337
var json = document.ToJson();
352338
var tempFileName = Path.GetTempFileName();
353339
File.WriteAllText(tempFileName, json);
354-
var targetPath = Path.Combine(rootFolder, serviceFolder, $"{instance.ServiceConfig.GeneratedFileName}.nswag");
355-
var nSwagFilePath = await context.HandlerHelper.AddFileAsync(tempFileName, targetPath);
340+
var targetPath = Path.Combine(rootFolder, serviceFolder, $"{serviceConfig.GeneratedFileName}.nswag");
341+
var nSwagFilePath = await Context.HandlerHelper.AddFileAsync(tempFileName, targetPath);
356342
if (File.Exists(tempFileName))
357343
{
358344
File.Delete(tempFileName);
359345
}
360346

361-
if (File.Exists(instance.SpecificationTempPath))
347+
if (File.Exists(Instance.SpecificationTempPath))
362348
{
363-
File.Delete(instance.SpecificationTempPath);
349+
File.Delete(Instance.SpecificationTempPath);
364350
}
365351

366352
return nSwagFilePath;
367353
}
368354

369-
internal async Task<string> ReGenerateCSharpFileAsync(ConnectedServiceHandlerContext context, Instance instance)
355+
internal async Task<string> ReGenerateCSharpFileAsync()
370356
{
371-
var serviceFolder = instance.Name;
372-
var rootFolder = context.HandlerHelper.GetServiceArtifactsRootFolder();
373-
var folderPath = context.ProjectHierarchy.GetProject().GetServiceFolderPath(rootFolder, serviceFolder);
357+
var folderPath = await GetReferenceFileFolderAsync();
374358

375-
var nSwagFilePath = Path.Combine(folderPath, $"{instance.ServiceConfig.GeneratedFileName}.nswag");
376-
var document = await NSwagDocument.LoadWithTransformationsAsync(nSwagFilePath, instance.ServiceConfig.Variables);
377-
document.Runtime = instance.ServiceConfig.Runtime;
359+
var nSwagFilePath = Path.Combine(folderPath, $"{Instance.ServiceConfig.GeneratedFileName}.nswag");
360+
var document = await NSwagDocument.LoadWithTransformationsAsync(nSwagFilePath, Instance.ServiceConfig.Variables);
361+
document.Runtime = Instance.ServiceConfig.Runtime;
378362
await document.ExecuteAsync();
379363
return document.SelectedSwaggerGenerator.OutputFilePath;
380364
}

0 commit comments

Comments
 (0)