This article describes the operation of a method-based static code analyzer for .NET that constructs in-memory method call networks of compiled assemblies. You will also see a concrete application of static code analysis to generate a website providing easy insights on a sample application.
- codeanalyzerandtodosample.zip
- CodeAnalyzer and Sample Solution.sln
- Generate.cmd
- Generator
- Output
- Blank.html
- co_CreateToDoItem(int,string,Nullable[DateTime])_ToDoItem.html
- co_DeleteToDoItem(int)_void.html
- co_FindUserByName(string)_User.html
- co_GetToDoItem(int)_ToDoItem.html
- co_GetUser(int)_User.html
- co_ListAllToDoItems()_IEnumerable[ToDoItem].html
- co_ListAllUsers()_IEnumerable[User].html
- co_ListDoneItemsForUser(int)_IEnumerable[ToDoItem].html
- co_ListToDoItemsForUser(int)_IEnumerable[ToDoItem].html
- co_ListUsersMatching(string)_IEnumerable[User].html
- co_MarkToDoItemDone(int)_void.html
- co_UpdateToDoItem(int,string,Nullable[DateTime])_void.html
- CodeModel.css
- CodeModel.js
- Content.html
- Index.html
- IndexTop.html
- so_CreateToDoItem(int,string,Nullable[DateTime])_ToDoItem.html
- so_DeleteToDoItem(int)_void.html
- so_FindUserByName(string)_User.html
- so_GetUser(int)_User.html
- so_ListAllUsers()_List[User].html
- so_ListDoneItemsForUser(int)_List[ToDoItem].html
- so_ListToDoItemsForUser(int)_List[ToDoItem].html
- so_ListUsersMatching(string)_List[User].html
- so_MarkToDoItemDone(int)_void.html
- so_UpdateToDoItem(int,string,Nullable[DateTime])_ToDoItem.html
- ui_CreateNewToDoItemClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_DeleteClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_InitializeComponent()_void.html
- ui_MarkDoneClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_RefreshToDoItems()_void.html
- ui_SaveClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_ToDoItemSelected(object,System.Windows.Controls.SelectionChangedEventArgs)_void.html
- ui_UserSelected(object,System.Windows.Controls.SelectionChangedEventArgs)_void.html
- ui_WindowLoaded(object,System.Windows.RoutedEventArgs)_void.html
- SampleApp
- LocalTestRun.testrunconfig
- ToDoApplication
- ToDoContract
- ToDoSample.vsmdi
- ToDoService
- ToDoUnitTests
- StaticCodeAnalyzer
- Arebis.CodeAnalysis.Static
- Arebis.Common
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Arebis.CodeAnalysis.Static;
using ToDoSample.Service;
using System.Data.Objects;
using ToDoSample.Contract;
using System.ServiceModel;
using System.Reflection;
namespace ToDoSample.UnitTests
{
[TestClass]
public class ToDoServiceCodeTest
{
#region Build CodeModel
private static CodeModel CodeModel;
[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
// Build the CodeModel:
StaticCodeAnalyzerSession session = new StaticCodeAnalyzerSession();
session.AddAssembly(typeof(ToDoServiceImplementation).Assembly);
session.AddAssembly(typeof(ObjectContext).Assembly);
session.AnalyzerFilter = new AnalyzerFilter();
CodeModel = new StaticCodeAnalyzer().Process(session);
// Mark service methods:
var qsrv = from m in CodeModel.Methods
where m.ImplementedInterfaceMethods.Select(im => im.DeclaringType == typeof(IToDoService)).Count() > 0
select m;
foreach (var method in qsrv)
method.Tags.Add("serviceimplementation");
// Mark entity framework save methods:
var qefs = from m in CodeModel.Methods
where m.Name == "SaveChanges"
&& m.DeclaringType == typeof(ObjectContext)
select m;
foreach (var method in qefs)
method.Tags.Add("savechanges");
}
internal class AnalyzerFilter : IAnalyzerFilter
{
#region IAnalyzerFilter Members
public bool ProcessAssembly(Assembly assembly)
{
return true;
}
public bool ProcessType(Type type)
{
// Skip all types in System.* namespaces except ObjectContext:
if (type.Namespace == null || (type.Namespace.StartsWith("System.") && (type.Name != "ObjectContext")))
return false;
else
return true;
}
public bool ProcessMethod(MethodBase method)
{
return true;
}
#endregion
}
#endregion
/// <summary>
/// Verifies that all service operations that perform a database mutation (insert/update/delete)
/// have the [OperationBehavior(TransactionScopeRequired = true)] attribute set.
/// </summary>
[TestMethod]
public void TransactionCodeTest()
{
bool hasErrors = false;
// For all service implementation methods:
foreach (ModelMethod m in CodeModel.Methods.WhereTagsContains("serviceimplementation"))
{
// If the method calls ObjectContext.SaveChanges:
if (m.GetAllCallsMethods().WhereTagsContains("savechanges").Count() > 0)
{
// Check if it has the [OperationBehavior(TransactionScopeRequired = true)] attribute set.
bool hasTransactionScopeRequired = false;
foreach (OperationBehaviorAttribute attr in m.MethodBase.GetCustomAttributes(typeof(OperationBehaviorAttribute), false))
{
if (attr.TransactionScopeRequired == true)
{
hasTransactionScopeRequired = true;
break;
}
}
// If not, report an error:
if (!hasTransactionScopeRequired)
{
hasErrors = true;
Console.WriteLine(
"Method {1} on {0} must have [OperationBehavior(TransactionScopeRequired = true)]",
m.DeclaringType,
m);
}
}
}
// Test fails if there were errors:
if (hasErrors)
Assert.Fail("Test failed, check Console Output for errors.");
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.