Skip to content

Commit cf7aa75

Browse files
authored
Merge pull request #7 from CodeFactoryLLC/StandardNDF
nuget release
2 parents 26b5ab5 + 13bc2d8 commit cf7aa75

20 files changed

+1123
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using CodeFactory.WinVs;
7+
using CodeFactory.WinVs.Models.CSharp;
8+
using CodeFactory.WinVs.Models.CSharp.Builder;
9+
10+
namespace CodeFactory.Automation.Standard.NDF.Logic
11+
{
12+
/// <summary>
13+
/// Logic for adding missing members.
14+
/// </summary>
15+
public static class AddMissingMembers
16+
{
17+
/// <summary>
18+
/// Name of the Microsoft logging library.
19+
/// </summary>
20+
public const string MicrosoftLoggingNamespace = "Microsoft.Extensions.Logging";
21+
22+
/// <summary>
23+
/// Name of the NDF namespace.
24+
/// </summary>
25+
public const string NDFNamespace = "CodeFactory.NDF";
26+
27+
/// <summary>
28+
/// Add missing interface members
29+
/// </summary>
30+
/// <param name="source">The CodeFactory automation for Visual Studio Windows</param>
31+
/// <param name="sourceCode">Source code model to be updated with add members in the target class.</param>
32+
/// <param name="updateClass">Class model to add missing members to.</param>
33+
/// <param name="supportsLogging">Flag that determines if logging is enabled.</param>
34+
/// <param name="loggerFieldName">Optional, the name of the field to use for logging.</param>
35+
/// <returns></returns>
36+
public static async Task<CsClass> AddMissingMembersStandardNDFAsync(this IVsActions source, CsSource sourceCode,
37+
CsClass updateClass, bool supportsLogging, string loggerFieldName = "_logger")
38+
{
39+
//Bounds checks to make sure all data needed is provided.
40+
if (sourceCode == null)
41+
throw new CodeFactoryException(
42+
"Visual Studio automation for CodeFactory was not provided cannot add missing members.");
43+
44+
if (sourceCode == null)
45+
throw new CodeFactoryException("No source code was provided, cannot add the missing members.");
46+
47+
if (updateClass == null)
48+
throw new CodeFactoryException(
49+
"No target class to add missing members was provided, cannot add the missing members.");
50+
51+
//Get the missing members to be added
52+
var missingMembers = updateClass.GetMissingInterfaceMembers();
53+
54+
//If no missing members are found just return the current class.
55+
if (!missingMembers.Any()) return updateClass;
56+
57+
//Creating the source code manager for the class.
58+
var manager = new SourceClassManager(sourceCode, updateClass, source);
59+
manager.LoadNamespaceManager();
60+
61+
62+
//Creating the blocks to be used for code generation
63+
ILoggerBlock loggerBlock = supportsLogging ? new LoggerBlockNDF(loggerFieldName) : null;
64+
65+
var boundsChecks = new IBoundsCheckBlock[]
66+
{
67+
new BoundsCheckBlockStringNDF(true, loggerBlock),
68+
new BoundsCheckBlockNullNDF(true, loggerBlock)
69+
};
70+
71+
var catchBlocks = new ICatchBlock[]
72+
{
73+
new CatchBlockManagedExceptionNDF(loggerBlock),
74+
new CatchBlockExceptionNDF(loggerBlock)
75+
};
76+
77+
ITryBlock tryBlock = new TryBlockStandard(loggerBlock, catchBlocks);
78+
79+
if(supportsLogging) await manager.UsingStatementAddAsync(MicrosoftLoggingNamespace);
80+
await manager.UsingStatementAddAsync(NDFNamespace);
81+
82+
//Creating the builders to generate code by member type.
83+
IMethodBuilder methodBuilder = new MethodBuilderStandard(loggerBlock, boundsChecks, tryBlock);
84+
IPropertyBuilder propertyBuilder = new PropertyBuilderStandard();
85+
IEventBuilder eventBuilder = new EventBuilderStandard();
86+
87+
//Process all missing properties.
88+
var missingProperties = missingMembers.Where(m => m.MemberType == CsMemberType.Property).Cast<CsProperty>()
89+
.ToList();
90+
91+
foreach (var missingProperty in missingProperties)
92+
{
93+
var propertySyntax = await propertyBuilder.BuildPropertyAsync(missingProperty, manager, 2);
94+
95+
if(propertySyntax == null) continue;
96+
97+
await manager.PropertiesAddAfterAsync(propertySyntax);
98+
99+
}
100+
101+
//Process all missing methods.
102+
var missingMethods = missingMembers.Where(m => m.MemberType == CsMemberType.Method).Cast<CsMethod>()
103+
.ToList();
104+
105+
foreach (var missingMethod in missingMethods)
106+
{
107+
var methodSyntax = await methodBuilder.BuildMethodAsync(missingMethod, manager, 2);
108+
109+
if(methodSyntax == null) continue;
110+
111+
await manager.MethodsAddAfterAsync(methodSyntax);
112+
}
113+
114+
//Process all missing events.
115+
var missingEvents = missingMembers.Where(m => m.MemberType == CsMemberType.Event).Cast<CsEvent>()
116+
.ToList();
117+
118+
foreach (var missingEvent in missingEvents)
119+
{
120+
var eventSyntax = await eventBuilder.BuildEventAsync(missingEvent, manager, 2);
121+
122+
if(eventSyntax == null) continue;
123+
124+
await manager.EventsAddAfterAsync(eventSyntax);
125+
}
126+
127+
return manager.Container;
128+
}
129+
}
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace CodeFactory.Automation.Standard.NDF.Logic
8+
{
9+
/// <summary>
10+
/// Data class that holds constants used in AspNet Delivery.
11+
/// </summary>
12+
public static class AspNetConstants
13+
{
14+
/// <summary>
15+
/// The name of the filed that holds the logger
16+
/// </summary>
17+
public const string FieldNameLogger = "_logger";
18+
19+
/// <summary>
20+
/// The full name of the library for logging.
21+
/// </summary>
22+
public const string MicrosoftExtensionLibraryForLoggingName = "Microsoft.Extensions.Logging.Abstractions";
23+
24+
/// <summary>
25+
/// Library name for the Microsoft Logger abstractions library.
26+
/// </summary>
27+
public const string MicrosoftLoggerLibraryName = "Microsoft.Extensions.Logging.Abstractions";
28+
29+
/// <summary>
30+
/// The default namespace for the Microsoft extensions logger implementation
31+
/// </summary>
32+
public const string MicrosoftLoggerNamespace = "Microsoft.Extensions.Logging";
33+
34+
/// <summary>
35+
/// The name of the interface for the Microsoft extensions logger.
36+
/// </summary>
37+
public const string MicrosoftLoggerInterfaceName = "ILogger";
38+
39+
/// <summary>
40+
/// The fully qualified name of the a aspnet core controller.
41+
/// </summary>
42+
public const string ControllerBaseName = "Microsoft.AspNetCore.Mvc.ControllerBase";
43+
44+
/// <summary>
45+
/// The full namespace for the mvc namespace.
46+
/// </summary>
47+
public const string MvcNamespace = "Microsoft.AspNetCore.Mvc";
48+
49+
/// <summary>
50+
/// Name for the abstract classes that support action result.
51+
/// </summary>
52+
public const string ActionResultClassName = "ActionResult";
53+
54+
/// <summary>
55+
/// Name of the interface for action results.
56+
/// </summary>
57+
public const string ActionResultInterfaceName = "IActionResult";
58+
59+
/// <summary>
60+
/// Namespace for tasks
61+
/// </summary>
62+
public const string SystemThreadingTasksNamespace = "System.Threading.Tasks";
63+
64+
/// <summary>
65+
/// Class name for the Task class.
66+
/// </summary>
67+
public const string TaskClassName = "Task";
68+
69+
/// <summary>
70+
/// Namespace for dependency injection.
71+
/// </summary>
72+
public const string DependencyInjectionAbstractions = "Microsoft.Extensions.DependencyInjection.Abstractions";
73+
74+
/// <summary>
75+
/// Namespace for configuration.
76+
/// </summary>
77+
public const string ConfigurationAbstractions = "Microsoft.Extensions.Configuration.Abstractions";
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using CodeFactory.WinVs.Models.CSharp;
7+
using CodeFactory.WinVs.Models.CSharp.Builder;
8+
using Microsoft.Extensions.Logging;
9+
10+
namespace CodeFactory.Automation.Standard.NDF.Logic
11+
{
12+
/// <summary>
13+
/// Null bounds check that support NDF logging and exceptions.
14+
/// </summary>
15+
internal class BoundsCheckBlockNullNDF:BaseBoundsCheckBlock
16+
{
17+
/// <summary>Initializes the base class for the bounds check.</summary>
18+
/// <param name="ignoreWhenDefaultValueIsSet">Flag that determines if the bounds checking should be ignored if a default value is set.</param>
19+
/// <param name="loggerBlock">Logger block used with bounds check logic.</param>
20+
public BoundsCheckBlockNullNDF(bool ignoreWhenDefaultValueIsSet, ILoggerBlock loggerBlock) : base(nameof(BoundsCheckBlockNullNDF), ignoreWhenDefaultValueIsSet, loggerBlock)
21+
{
22+
//Intentionally blank
23+
}
24+
25+
/// <summary>
26+
/// Generates the bounds check syntax if the parameter meets the criteria for a bounds check.
27+
/// </summary>
28+
/// <param name="sourceMethod">The target method the parameter belongs to.</param>
29+
/// <param name="checkParameter">The parameter to build the bounds check for.</param>
30+
/// <returns>Returns a tuple that contains a boolean that determines if the bounds check syntax was created for the parameter.</returns>
31+
public override (bool hasBoundsCheck, string boundsCheckSyntax) GenerateBoundsCheck(CsMethod sourceMethod, CsParameter checkParameter)
32+
{
33+
//bounds check to make sure we have parameter data.
34+
if (checkParameter == null) return (false, null);
35+
36+
if(checkParameter.ParameterType.IsValueType) return (false, null);
37+
38+
if(checkParameter.HasDefaultValue) return (false, null);
39+
40+
SourceFormatter formatter = new SourceFormatter();
41+
42+
formatter.AppendCodeLine(0,$"if ({checkParameter.Name} == null)");
43+
formatter.AppendCodeLine(0,"{");
44+
if (LoggerBlock != null)
45+
{
46+
var errorMessage = $"$\"The parameter {{nameof({checkParameter.Name})}} was not provided. Will raise an argument exception\"";
47+
formatter.AppendCodeLine(1,LoggerBlock.GenerateLogging(LogLevel.Error, errorMessage,true));
48+
formatter.AppendCodeLine(1, LoggerBlock.GenerateExitLogging(LogLevel.Error,sourceMethod.Name));
49+
}
50+
formatter.AppendCodeLine(1,$"throw new ArgumentNullException(nameof({checkParameter.Name}));");
51+
formatter.AppendCodeLine(0,"}");
52+
53+
return (true,formatter.ReturnSource());
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using CodeFactory.WinVs.Models.CSharp;
7+
using CodeFactory.WinVs.Models.CSharp.Builder;
8+
using Microsoft.Extensions.Logging;
9+
10+
namespace CodeFactory.Automation.Standard.NDF.Logic
11+
{
12+
/// <summary>
13+
/// String bounds check that supports NDF logging and exception management.
14+
/// </summary>
15+
public class BoundsCheckBlockStringNDF:BaseBoundsCheckBlock
16+
{
17+
/// <summary>Initializes the base class for the bounds check.</summary>
18+
/// <param name="ignoreWhenDefaultValueIsSet">Flag that determines if the bounds checking should be ignored if a default value is set.</param>
19+
/// <param name="loggerBlock">Logger block used with bounds check logic.</param>
20+
public BoundsCheckBlockStringNDF(bool ignoreWhenDefaultValueIsSet, ILoggerBlock loggerBlock) : base(nameof(BoundsCheckBlockStringNDF), ignoreWhenDefaultValueIsSet, loggerBlock)
21+
{
22+
}
23+
24+
/// <summary>
25+
/// Generates the bounds check syntax if the parameter meets the criteria for a bounds check.
26+
/// </summary>
27+
/// <param name="sourceMethod">The target method the parameter belongs to.</param>
28+
/// <param name="checkParameter">The parameter to build the bounds check for.</param>
29+
/// <returns>Returns a tuple that contains a boolean that determines if the bounds check syntax was created for the parameter.</returns>
30+
public override (bool hasBoundsCheck, string boundsCheckSyntax) GenerateBoundsCheck(CsMethod sourceMethod, CsParameter checkParameter)
31+
{
32+
//bounds check to make sure we have parameter data.
33+
if (checkParameter == null) return (false, null);
34+
35+
if(!(checkParameter.ParameterType.Namespace == "System" & checkParameter.ParameterType.Name == "String")) return (false, null);
36+
37+
if(checkParameter.HasDefaultValue) return (false, null);
38+
39+
SourceFormatter formatter = new SourceFormatter();
40+
41+
formatter.AppendCodeLine(0,$"if (string.IsNullOrEmpty({checkParameter.Name}))");
42+
formatter.AppendCodeLine(0,"{");
43+
if (LoggerBlock != null)
44+
{
45+
var errorMessage =
46+
$"$\"The parameter {{nameof({checkParameter.Name})}} was not provided. Will raise an argument exception\"";
47+
formatter.AppendCodeLine(1,LoggerBlock.GenerateLogging(LogLevel.Error, errorMessage,true));
48+
formatter.AppendCodeLine(1, LoggerBlock.GenerateExitLogging(LogLevel.Error,sourceMethod.Name));
49+
}
50+
formatter.AppendCodeLine(1,$"throw new ArgumentException(nameof({checkParameter.Name}));");
51+
formatter.AppendCodeLine(0,"}");
52+
53+
return (true,formatter.ReturnSource());
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using CodeFactory.WinVs.Models.CSharp.Builder;
7+
using Microsoft.Extensions.Logging;
8+
9+
namespace CodeFactory.Automation.Standard.NDF.Logic
10+
{
11+
/// <summary>
12+
/// CodeBlock that builds a catch block for DBUpdateException and returns a NDF managed exception.
13+
/// </summary>
14+
public class CatchBlockDBUpdateExceptionNDF:BaseCatchBlock
15+
{
16+
17+
/// <summary>
18+
/// Creates a instances of the <see cref="CatchBlockDBUpdateExceptionNDF"/>
19+
/// </summary>
20+
/// <param name="loggerBlock">Optional, logger block to use for logging in the catch block.</param>
21+
public CatchBlockDBUpdateExceptionNDF(ILoggerBlock loggerBlock = null) : base(loggerBlock)
22+
{
23+
//intentionally bank
24+
}
25+
26+
/// <summary>Builds the catch block</summary>
27+
/// <param name="syntax">Syntax to be injected into the catch block, optional parameter.</param>
28+
/// <param name="multipleSyntax">Multiple syntax statements has been provided to be used by the catch block,optional parameter.</param>
29+
/// <param name="memberName">Optional parameter that determines the target member the catch block is implemented in.</param>
30+
/// <returns>Returns the generated catch block</returns>
31+
protected override string BuildCatchBlock(string syntax = null, IEnumerable<NamedSyntax> multipleSyntax = null, string memberName = null)
32+
{
33+
SourceFormatter formatter = new SourceFormatter();
34+
35+
formatter.AppendCodeLine(0,"catch (DbUpdateException updateDataException)");
36+
formatter.AppendCodeLine(0,"{");
37+
formatter.AppendCodeLine(1, "var sqlError = updateDataException.InnerException as SqlException;");
38+
formatter.AppendCodeLine(1);
39+
formatter.AppendCodeLine(1,"if (sqlError == null)");
40+
formatter.AppendCodeLine(1,"{");
41+
if (LoggerBlock != null)
42+
{
43+
formatter.AppendCodeLine(2, LoggerBlock.GenerateLogging(LogLevel.Error, "The following database error occurred.",false,"updateDataException"));
44+
formatter.AppendCodeLine(2, LoggerBlock.GenerateExitLogging(LogLevel.Error, memberName));
45+
}
46+
formatter.AppendCodeLine(2, "throw new DataException();");
47+
formatter.AppendCodeLine(1,"}");
48+
49+
50+
if (LoggerBlock != null)
51+
{
52+
formatter.AppendCodeLine(1, LoggerBlock.GenerateLogging(LogLevel.Error, "The following SQL exception occurred.",false, "sqlError"));
53+
formatter.AppendCodeLine(1, LoggerBlock.GenerateExitLogging(LogLevel.Error, memberName));
54+
}
55+
formatter.AppendCodeLine(1,"sqlError.ThrowManagedException();");
56+
formatter.AppendCodeLine(0,"}");
57+
58+
return formatter.ReturnSource();
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)