Add calling NUnit test to NLog output - nunit

I am running tests through NUnit and want to have NLog messages quickly tell me the calling test on each log message. Something like
<target xsi:type="File"
layout="${longdate} ${someMagic} ${message}"
/>
Is there an easy way to do that without diving too deep into NLog code?

Here's a working solution: a set of extension methods that wrap NLog ILogger.Error(..) method and the likes, looking up the stack for NUnit [Test] or [TestCase] Attributes
public static void XError(this ILogger log, String message)
{
if (log.IsErrorEnabled == false)
return;
var prefix = GetCallerTestDescription();
log.Error("[{0}] {1}", prefix, message);
}
private static string GetCallerTestDescription()
{
var stack = new StackTrace(false).GetFrames();
if (stack != null)
{
foreach (var frame in stack)
{
var method = frame.GetMethod();
var testAttributes = method.GetCustomAttributes<TestAttribute>();
if (testAttributes != null && testAttributes.Any())
{
return method.Name;
}
var tcAttributes = method.GetCustomAttributes<TestCaseAttribute>();
if (tcAttributes != null && tcAttributes.Any())
{
return method.Name;
}
}
}

Related

Working on pre-operation plug-in to update "Modified By" field in MSCRM -- Need help fixing code

I am trying to update the "Modified By" field based on a text field called "Prepared By", which contains the name of a user. I've created a pre-operation plug-in to do this and believe I am close to done. However, the "Modified By" field is still not successfully getting updated. I am relatively new to coding and CRM, and could use some help modifying the code and figuring out how I can get this to work.
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Linq;
namespace TimClassLibrary1.Plugins
{
public class CreateUpdateContact : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = factory.CreateOrganizationService(context.UserId);
tracingService.Trace("Start plugin");
tracingService.Trace("Validate Target");
if (!context.InputParameters.Contains("Target") || !(context.InputParameters["Target"] is Entity))
return;
tracingService.Trace("Retrieve Target");
var target = (Entity)context.InputParameters["Target"];
String message = context.MessageName.ToLower();
SetCreatedByAndModifiedBy(tracingService, service, target, message);
}
private void SetCreatedByAndModifiedBy(ITracingService tracingService, IOrganizationService service, Entity target, string message)
{
tracingService.Trace("Start SetPriceList");
tracingService.Trace("Validate Message is Create or Update");
if (!message.Equals("create", StringComparison.OrdinalIgnoreCase) && !message.Equals("update", StringComparison.OrdinalIgnoreCase))
return;
tracingService.Trace("Retrieve Attributes");
var createdByReference = target.GetAttributeValue<EntityReference>("new_createdby");
var modifiedByReference = target.GetAttributeValue<EntityReference>("new_modifiedby");
tracingService.Trace("Retrieve And Set User for Created By");
RetrieveAndSetUser(tracingService, service, target, createdByReference, "createdby");
tracingService.Trace("Retrieve And Set User for Modified By");
RetrieveAndSetUser(tracingService, service, target, modifiedByReference, "modifiedby");
}
private void RetrieveAndSetUser(ITracingService tracingService, IOrganizationService service, Entity target, EntityReference reference, string targetAttribute)
{
tracingService.Trace("Validating Reference");
if (reference == null)
return;
tracingService.Trace("Retrieving and Validating User");
var user = RetrieveUserByName(service, reference.Name, new ColumnSet(false));
if (user == null)
return;
tracingService.Trace("Setting Target Attribute");
target[targetAttribute] = user.ToEntityReference();
}
private Entity RetrieveUserByName(IOrganizationService service, string name, ColumnSet columns)
{
var query = new QueryExpression
{
EntityName = "systemuser",
ColumnSet = columns,
Criteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = "fullname",
Operator = ConditionOperator.Equal,
Values = { name }
}
}
}
};
var retrieveResponse = service.RetrieveMultiple(query);
if (retrieveResponse.Entities.Count == 1)
{
return retrieveResponse.Entities.FirstOrDefault();
}
else
{
return null;
}
}
}
}
If you do get use from method Retreiveusernyname then you have to use below code
target[“modifiedby”] = new EntityRefrence(user.logicalname,user.id);
I don't see anything obviously wrong with your update, however you are taking a complicated and unnecessary step with your RetrieveUserByName() method. You already have EntityReference objects from your new_createdby and new_modifiedby fields, you can simply assign those to the target:
if (message.Equals("create", StringComparison.OrdinalIgnoreCase))
{
target["createdby"] = target["new_createdby];
}
else if (message.Equals("update", StringComparison.OrdinalIgnoreCase))
{
target["modifiedby"] = target["new_modifiedby];
}
If new_createdby and new_modifiedby are not entity references, then that would explain why your existing code does not work, if they are, then use my approach.

Unit Testing (xUnit) NLog logging service under .NET Core

.NET Core 2.1
NLog 4.6
xUnit 2.3.1
I have class library with xUnit that calls a separate library that contains REST-based APIs that is responsible for creating various logs for the system.
Since the unit test class library calls the REST-based API controller directly, the class's Startup class isn't loaded so I don't believe NLog is being configured. This will need to be done within the unit test class library but I cannot seem to figure that out.
I am able to load the REST-based API nlog configuration from the calling library and then execute NLogs directly from the LogManager but the NLog implementation explicitly used within the REST-based API does not log nor does any error occur.
If I use a soap client such as SOAPUI and call the REST's class library, the logs are created as expected. This means the unit test class library isn't configuring logging correctly.
// Unit Test's base class for wiring up DI and other configuration including Logging
public BaseTests()
{
// Configuration
string loggingServiceAPIPath = #"../../../../../../LoggingService/API/CM.LoggingService.API";
var builder = new ConfigurationBuilder().SetBasePath(Path.GetFullPath(loggingServiceAPIPath)).AddJsonFile("appsettings.json");
var configuration = builder.Build();
// Configure logging
LogManager.Configuration = new XmlLoggingConfiguration(Path.GetFullPath($"{ loggingServiceAPIPath }/nlog.config"));
// Application-Wide Services
IServiceCollection services = new ServiceCollection();
services.AddMvc();
services.AddLogging();
services.AddSingleton(configuration);
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<IMemoryCache, MemoryCache>();
services.AddSingleton<ILoggingServiceController, LoggingServiceController>();
services.AddApplicationServices();
services.AddOptions();
services.ConfigureConfigServerClientOptions(configuration);
services.AddConfiguration(configuration);
services.Configure<ConfigServerData>(configuration);
this._serviceProvider = services.BuildServiceProvider();
// Persist configuration
IMemoryCache iMemoryCache = this._serviceProvider.GetService<IMemoryCache>();
IOptionsSnapshot<ConfigServerData> iConfigServerData = this._serviceProvider.GetService<IOptionsSnapshot<ConfigServerData>>();
if (iMemoryCache != null && iConfigServerData != null) { iMemoryCache.Set(CM.Common.Constants.ConfigKey, iConfigServerData.Value); }
}
// Unit Test being called from a class library
[Fact]
public async void Test_LogDebugSuccess()
{
LoggingServiceRequest request = new LoggingServiceRequest
{
ErrorException = new Exception(),
Message = System.Reflection.MethodBase.GetCurrentMethod().Name
};
// This is not capturing NLog probably due to not being called in a hosted environment.
var result = await
this._iLoggingServiceController.LogDebug(request);
// Assert
Assert.Null(result as NotFoundObjectResult);
var okObjectResult = result as OkObjectResult;
Assert.True((okObjectResult != null &&
okObjectResult.StatusCode.GetValueOrDefault(0) == Convert.ToInt32(System.Net.HttpStatusCode.OK)), "Log was not created.");
}
// LoggingService
public class Program
{
/// <summary>
/// Main
/// </summary>
/// <param name="args">Arguments</param>
public static void Main(string[] args)
{
// NLog: setup the logger first to catch all errors
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Debug("Init Main");
Program.BuildWebHost(args).Run();
}
catch (Exception ex)
{
logger.Error(ex, $"Stopped program because of exception: { ex.Message }");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
/// <summary>
/// Build WebHost
/// </summary>
/// <param name="args">Arguments</param>
/// <returns>WebHost interface</returns>
public static IWebHost BuildWebHost(string[] args)
{
try
{
var config = WebHost.CreateDefaultBuilder(args)
.CaptureStartupErrors(false)
.AddConfigServer()
.UseStartup<Startup>()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog() // NLog: setup NLog for Dependency injection
.Build();
return config;
}
catch (Exception ex)
{
throw ex;
}
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(
config =>
{
config.Filters.Add(typeof(CustomExceptionFilter));
}
);
// Add memory cache
services.AddMemoryCache();
services.AddMvc();
services.AddCors(o => o.AddPolicy("corspolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()));
services.AddSingleton(this.Configuration);
// Application-Wide Services
services.AddApplicationServices();
// Configuration
services.AddOptions();
services.ConfigureConfigServerClientOptions(this.Configuration);
services.AddConfiguration(this.Configuration);
services.Configure<ConfigServerData>(this.Configuration);
// Configure Swagger
services.AddSwaggerGen(s =>
{
s.SwaggerDoc("v1", new Info { Title = "CM LoggingService APIs", Version = "V1" });
});
}
public void Configure(IApplicationBuilder iApplicationBuilder, IHostingEnvironment iHostingEnvironment, IConfigurationManager iConfigurationManager, IMemoryCache iMemoryCache, IApplicationLifetime iApplicationLifetime, ILogger<LoggingServiceController> iLogger)
{
if (iHostingEnvironment.IsDevelopment() == true)
{
iApplicationBuilder.UseDeveloperExceptionPage();
iApplicationBuilder.UseStatusCodePages();
iApplicationBuilder.UseDatabaseErrorPage();
iApplicationBuilder.UseBrowserLink();
}
if (iHostingEnvironment.IsProduction() == false)
{
// Swagger - API Documentation
iApplicationBuilder.UseSwagger();
iApplicationBuilder.UseSwaggerUI(s =>
{
s.SwaggerEndpoint("./v1/swagger.json", "CM LoggingService APIs");
});
}
// Persist Steeltoe configuration
iConfigurationManager.Init();
if (iMemoryCache != null && iConfigurationManager != null) { iMemoryCache.Set(CM.Common.Constants.MEMORYCACHE_CONFIGURATIONMANAGER_KEY, iConfigurationManager); }
iConfigurationManager.LogConfiguration();
// Configure global exception handler
iApplicationBuilder.ConfigureExceptionHandler(iLogger);
iApplicationBuilder.UseMvc();
// Application Events
iApplicationLifetime.ApplicationStarted.Register(this.OnApplicationStarted);
iApplicationLifetime.ApplicationStopped.Register(this.OnApplicationStopping);
}
public class LoggingServiceController : Controller, ILoggingServiceController
{
private readonly ILogger<LoggingServiceController> _iLogger = null;
private readonly ILoggingServiceDomainController _iLoggingServiceDomainController = null;
public LoggingServiceController(ILogger<LoggingServiceController> iLogger, ILoggingServiceDomainController iLoggingServiceDomainController)
{
this._iLogger = iLogger;
this._iLoggingServiceDomainController = iLoggingServiceDomainController;
}
[HttpPost("LogError")]
public async Task<IActionResult> LogError([FromBody] LoggingServiceRequest request)
{
bool result = false;
try
{
// Validation
if (ModelState.IsValid == false)
{
this._iLogger.LogError($"{ CM.Common.ExceptionHandling.ExceptionTypes.VALIDATION }: { typeof(LoggingServiceRequest).Name } (request) is not valid.");
return BadRequest();
}
// Log
result = this._iLogger.LogError(request.ErrorException, request.Message, request.Args);
if (result == false) { return NotFound(); }
}
catch (Exception ex)
{
this._iLogger.LogError(ex, $"{ CM.Common.ExceptionHandling.ExceptionTypes.UNSPECIFIED }: { ex.Message }");
}
return Ok(result);
}
}

Unity3d app for UWP freeze when using SerialDevice

I have a piece of code that I want to use with Unity 2018.2.14.f1.
#if UNITY_WSA && !UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
namespace SerialForUWP
{
public class SerialComHelper
{
public async static Task<string[]> GetPorts()
{
var serials = SerialDevice.GetDeviceSelector();
var coms = await DeviceInformation.FindAllAsync(serials);
List<string> results = new List<string>();
foreach (var device in coms)
{
using (var serialDevice = await SerialDevice.FromIdAsync(device.Id))
{
if (serialDevice != null)
{
var port = serialDevice.PortName;
results.Add(port.ToString());
}
}
}
return results.ToArray();
}
}
}
#endif
I compile for UWP using IL2CPP :
I also already updated the manifest of the cpp projet :
<DeviceCapability Name="serialcommunication">
<Device Id="any">
<Function Type="name:serialPort" />
</Device>
</DeviceCapability>
As soon as I try to use the GetPorts() function my app freeze.
void Update()
{
text.text = Time.time.ToString();
if (Input.GetKeyUp(KeyCode.Space))
{
try
{
#if UNITY_WSA && !UNITY_EDITOR
foreach (var com in SerialForUWP.SerialComHelper.GetPorts().Result)
{
text.text = com;
}
#endif
}
catch (Exception ex)
{
text.text = ex.ToString();
}
}
}
I got no error, no exception.
Can anyone help please ?
To get the exceptions use:
Debug.Log(ex.ToString()) instead of Text.text = ex.ToString()
According to this answer I can't use .Result

Review of Connection handling and Data access layer using C#, sql server compact 3.5

I am developing a stand alone application, using sql server compact 3.5 sp2 which runs in process. No Database writes involved. Its purely a reporting application. Read many articles about reusing open db connections in case of sql compact(connection pooling) due to its different behavior from sql server.
Quoting the comments from a quiz opened by Erik Ejlskov Jensen Link, where its discussed an open early close late strategy for sql server compact databases. Based on this, with my limited experience I have implemented a not so complex Connection handling+Data access layer. Basically I am unsure if i am writing it in a recommended way. Please could any one point me in the right direction with rooms for improvement in this connection handling approach i have written?
The DbConnection class
public class FkDbConnection
{
private static SqlCeConnection conn;
private static DataTable table;
private static SqlCeCommand cmd;
~FkDbConnection() { conn = null; }
//This will be called when the main winform loads and connection will be open as long as the main form is open
public static string ConnectToDatabase()
{
try {
conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["Connstr"].ConnectionString);
if (conn.State == ConnectionState.Closed || conn.State == ConnectionState.Broken)
{
conn.Open();
}
return "Connected";
}
catch(SqlCeException e) { return e.Message; }
}
public static void Disconnect()
{
if (conn.State == ConnectionState.Open || conn.State == ConnectionState.Connecting || conn.State == ConnectionState.Fetching)
{
conn.Close();
conn.Dispose();
//conn = null; //does conn have to be set to null?
}
//else the connection might be already closed due to failure in opening it
else if (conn.State == ConnectionState.Closed) {
conn.Dispose();
//conn = null; //does conn have to be set to null?
}
}
/// <summary>
/// Generic Select DataAccess
/// </summary>
/// <param name="sql"> the sql query which needs to be executed by command object </param>
public static DataTable ExecuteSelectCommand(SqlCeCommand comm)
{
if (conn != null && conn.State == ConnectionState.Open)
{
#region block using datareader
using (table = new DataTable())
{
//using statement needed for reader? Its closed below
using (SqlCeDataReader reader = comm.ExecuteReader())
{
table.Load(reader);
reader.Close(); //is it needed?
}
}
#endregion
# region block using dataadpater
//I read DataReader is faster?
//using (SqlCeDataAdapter sda = new SqlCeDataAdapter(cmd))
//{
// using (table = new DataTable())
// {
// sda.Fill(table);
// }
//}
#endregion
//}
}
return table;
}
/// <summary>
/// Get Data
/// </summary>
/// <param name="selectedMPs"> string csv, generated from a list of selected posts(checkboxes) from the UI, which forms the field names used in SELECT </param>
public static DataTable GetDataPostsCars(string selectedMPs)
{
DataTable dt;
//i know this it not secure sql, but will be a separate question to pass column names to select as parameters
string sql = string.Format(
"SELECT " + selectedMPs + " "+
"FROM GdRateFixedPosts");
using (cmd = new SqlCeCommand(sql,conn))
{
cmd.CommandType = CommandType.Text;
//cmd.Parameters.Add("#fromDateTime",DbType.DateTime);
//cmd.Parameters.Add("#toDateTime",DbType.DateTime);
dt = ExecuteSelectCommand(cmd);
}
return dt;
}
}
The Main UI (Form) in which connection opened, for connection to be open through out. 2 other reporting forms are opened from here. Closing main form closes all, at which point connection is closed and disposed.
private void FrmMain_Load(object sender, EventArgs e)
{
string str = FkDbConnection.ConnectToDatabase();
statStDbConnection.Items[0].Text = str;
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
FkDbConnection.Disconnect();
}
Comments, improvements on this connection class much appreciated. See my questions also inline code
Thank you.
Updated classes as per Erik's suggestion. with a correction on ExecuteSelectCommand() and an additional class which will instantiate command objs in "using" and pass data to the UI. I intent to add separate GetDataForFormX() methods since the dynamic sql for each form may differ. Hope this is ok?
Correction to Erik's code:
public static DataTable ExecuteSelectCommand(SqlCeCommand comm)
{
var table = new DataTable();
if (conn != null && conn.State == ConnectionState.Open)
{
comm.Connection = conn;
using (SqlCeDataReader reader = comm.ExecuteReader())
{
table.Load(reader);
}
}
return table;
}
New FkDataAccess class for passing Data to UI
public class FkDataAccess
{
public static DataTable GetDataPostsCars(string selectedMPs)
{
var table = new DataTable();
string sql = string.Format(
"SELECT " + selectedMPs + " " +
"FROM GdRateFixedPosts");
if (FkDbConnection.conn != null && FkDbConnection.conn.State == ConnectionState.Open)
{
using (SqlCeCommand cmd = new SqlCeCommand(sql, FkDbConnection.conn))
{
cmd.CommandType = CommandType.Text;
//cmd.Parameters.Add("#fromDateTime",DbType.DateTime);
table = FkDbConnection.ExecuteSelectCommand(cmd);
}
}
return table;
}
//public static DataTable GetDataXY(string selectedvals)
// and so on
}
Too much code in your data access class, makes it unreadable and hard to maintain
The SqlCeonnection object will be disposed when you close it (and when the app closes)
You cannot dispose the DataTable if you want to use it elsewhere, and it is an completely managed object anyway.
It is a good pattern to limit your classes to a single responsibility
public class FkDbConnection
{
private static SqlCeConnection conn;
~FkDbConnection() { conn = null; }
//This will be called when the main winform loads and connection will be open as long as the main form is open
public static void ConnectToDatabase()
{
// Handle failure to open in the caller
conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["Connstr"].ConnectionString);
conn.Open();
}
public static void Disconnect()
{
if (conn != null)
{
conn.Close();
}
}
public static DataTable ExecuteSelectCommand(SqlCeCommand comm)
{
var table = new DataTable();
if (conn != null && conn.State == ConnectionState.Open)
{
comm.Connection = conn;
using (SqlCeDataReader reader = comm.ExecuteReader())
{
table.Load(reader);
}
}
return table;
}
private void FrmMain_Load(object sender, EventArgs e)
{
try
{
FkDbConnection.ConnectToDatabase();
statStDbConnection.Items[0].Text = "Connected";
}
catch (Exception ex)
{
//Inform use that we canot proceed, what she can do to remedy, and exit
}
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
FkDbConnection.Disconnect();
}

Is EntityReference.Load checking for EntityReference.IsLoaded?

Hi I was wondering if EntityReference.Load method includes
If Not ref.IsLoaded Then ref.Load()
My question is basically:
Dim person = Context.Persons.FirstOrDefault
person.AddressReference.Load()
person.AddressReference.Load() 'Does it do anything?
It does Load again. I verified this by Profiler and it shown two queries. Default merge option is MergeOption.AppendOnly and it doesn't prevent from querying again. Code from Reflector:
public override void Load(MergeOption mergeOption)
{
base.CheckOwnerNull();
ObjectQuery<TEntity> query = base.ValidateLoad<TEntity>(mergeOption, "EntityReference");
base._suppressEvents = true;
try
{
List<TEntity> collection = new List<TEntity>(RelatedEnd.GetResults<TEntity>(query));
if (collection.Count > 1)
{
throw EntityUtil.MoreThanExpectedRelatedEntitiesFound();
}
if (collection.Count == 0)
{
if (base.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
{
throw EntityUtil.LessThanExpectedRelatedEntitiesFound();
}
if ((mergeOption == MergeOption.OverwriteChanges) || (mergeOption == MergeOption.PreserveChanges))
{
EntityKey entityKey = ObjectStateManager.FindKeyOnEntityWithRelationships(base.Owner);
EntityUtil.CheckEntityKeyNull(entityKey);
ObjectStateManager.RemoveRelationships(base.ObjectContext, mergeOption, (AssociationSet) base.RelationshipSet, entityKey, (AssociationEndMember) base.FromEndProperty);
}
base._isLoaded = true;
}
else
{
base.Merge<TEntity>(collection, mergeOption, true);
}
}
finally
{
base._suppressEvents = false;
}
this.OnAssociationChanged(CollectionChangeAction.Refresh, null);
}
Just for reference for anyone else finding the accepted answer, here is the extension method I created for my current project.
using System.Data.Objects.DataClasses;
namespace ProjectName
{
public static class EntityFrameworkExtensions
{
public static void EnsureLoaded<TEntity>(this EntityReference<TEntity> reference)
where TEntity : class, IEntityWithRelationships
{
if (!reference.IsLoaded)
reference.Load();
}
}
}
And usage:
Patient patient = // get patient
patient.ClinicReference.EnsureLoaded();
patient.Clinic.DoStuff();