Entity Framework 4.1 - EFTracingProvider - c#

Is there a way to make the EFTracing provider work with EF 4.1?
EFTracing seems to need an objectcontext and I use dbcontext.
Thanks in advance!

Yes, you can. I'm using the community version with both database-first DbContexts and code-first DbContexts. This answer is based on a discussion thread on the project site.
For database-first/designer DbContexts (via ADO.NET DbContext Generator templates), you can simply add the following constructor:
public abstract class MyDbContext : DbContext
{
protected MyDbContext(string nameOrConnectionString)
: base(EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString), true)
{
// enable sql tracing
((IObjectContextAdapter) this).ObjectContext.EnableTracing();
}
}
For code first DbContexts its a bit more complicated since the EFTracingProvider wants a full entity connection string. You have to create an instance of EFTracingConnection manually. The following example will work for both database first and code first contexts.
public abstract class MyDbContext : DbContext
{
protected MyDbContext(string nameOrConnectionString)
: base(CreateTracingConnection(nameOrConnectionString), true)
{
// enable sql tracing
((IObjectContextAdapter) this).ObjectContext.EnableTracing();
}
private static DbConnection CreateTracingConnection(string nameOrConnectionString)
{
try
{
// this only supports entity connection strings http://msdn.microsoft.com/en-us/library/cc716756.aspx
return EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString);
}
catch (ArgumentException)
{
// an invalid entity connection string is assumed to be a normal connection string name or connection string (Code First)
ConnectionStringSettings connectionStringSetting =
ConfigurationManager.ConnectionStrings[nameOrConnectionString];
string connectionString;
string providerName;
if (connectionStringSetting != null)
{
connectionString = connectionStringSetting.ConnectionString;
providerName = connectionStringSetting.ProviderName;
}
else
{
providerName = "System.Data.SqlClient";
connectionString = nameOrConnectionString;
}
return CreateTracingConnection(connectionString, providerName);
}
}
private static EFTracingConnection CreateTracingConnection(string connectionString, string providerInvariantName)
{
// based on the example at http://jkowalski.com/2010/04/23/logging-sql-statements-in-entity-frameworkcode-first/
string wrapperConnectionString =
String.Format(#"wrappedProvider={0};{1}", providerInvariantName, connectionString);
EFTracingConnection connection =
new EFTracingConnection
{
ConnectionString = wrapperConnectionString
};
return connection;
}
}

Whilst the previous answers work, I've found them problematic, a much simpler solution is to use the Clutch.Diagnostics.EntityFramework package from NuGet that uses MiniProfiler behind the scenes. It is significantly simpler to get working than EFTracingProvider, and a much more flexible solution.
The project is on GitHub at https://github.com/Kukkimonsuta/Clutch
For EFTracingProvider like functionality install the NuGet package and then implement IDbTracingListener like this:
using System;
using System.Data.Common;
using System.Diagnostics;
using Clutch.Diagnostics.EntityFramework;
/// <summary>
///
/// </summary>
public class DbTracingListener : IDbTracingListener
{
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
/// <param name="result"></param>
/// <param name="duration"></param>
public void CommandExecuted(DbConnection connection, DbCommand command, object result, TimeSpan duration)
{
Debug.WriteLine(command.CommandText);
Debug.WriteLine(string.Format("Executed in: {0}", duration));
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
public void CommandExecuting(DbConnection connection, DbCommand command)
{
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
/// <param name="exception"></param>
/// <param name="duration"></param>
public void CommandFailed(DbConnection connection, DbCommand command, Exception exception, TimeSpan duration)
{
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
/// <param name="result"></param>
/// <param name="duration"></param>
public void CommandFinished(DbConnection connection, DbCommand command, object result, TimeSpan duration)
{
}
}

If you are using DBContext and MVC Model First, meaning using EntityConnections then the following sample code should be all you need:
public partial class BrickHouseFitnessContext : DbContext
{
public BrickHouseFitnessContext(): base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(ConfigurationManager.ConnectionStrings["BrickHouseFitnessContext"].ConnectionString, "EFTracingProvider"), true)
{
}
Also:
In the Web.Config file add the following sections:
<system.data>
<DbProviderFactories>
<add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>
and:
<add key="EFTracingProvider.logToConsole" value="true" />
<add key="EFTracingProvider.logToFile" value="C:\BrickHouseFitnessSqlLog.txt" />
There is no need to include the ExtendedEntities or the other ObjectContext derived class mentioned in the original article. Run that code and you should see your log file as specified, with all the SQL commands in it. I am bypassing database intialization when tracing is enabled,

Related

Generic implementation to Avoid Lazy Loading in EF with multiple Database Context (using partial class)

In my project I do have many Database Contexts.
1. MyContext1
2. MyContext2
3. MyContext3
I am currently using database first approach (edmx based).
As part of edmx creation all these contexts are created. I would like to disable lazy loading for all these contexts.
I thought of writing a partial class for this. So for each Context there will be a partial class and which is responsible for disabling the lazy loading.
My current approach is something like below
[DbConfigurationType(typeof(InterceptorConfiguration))]
public partial class MyContext1 : DbContext
{
public static MyContext1 Create()
{
var applicationDbContext = new MyContext1();
applicationDbContext.Configuration.LazyLoadingEnabled = false;
return applicationDbContext;
}
}
Here i do have static method where i manually create instance of context and apply the configurations and returning it. Is there any other way to do this without creating a direct instance in the partial class?
Since there is already a default constructor in the edmx auto generated class I cannot write a constructor in the partial class which I have created.
I can disable this one in service layer, but since this one is an existing project I dont want to touch everywhere. So is there any better solution to do the same ?
Since this one is an existing application and it has many edmx files I cannot edit/change anything in the edmx including t4 template
Finally got a solution.
Since I am using Simple Injector Dependency Injection package in my solution.
I have created a provider for getting the instance at run time.
public sealed class DbContextProvider<T> : IDbContextProvider<T>
where T : DbContext
{
/// <summary>
/// The producer
/// </summary>
private readonly InstanceProducer producer;
/// <summary>
/// Initializes a new instance of the <see cref="DbContextProvider{T}"/> class.
/// </summary>
/// <param name="container">The container.</param>
/// <exception cref="InvalidOperationException">You forgot to register {typeof(T).Name}. Please call: " +
/// $"container.Register<{typeof(T).Name}>(Lifestyle.Scope);</exception>
public DbContextProvider(Container container)
{
this.producer = container.GetCurrentRegistrations()
.FirstOrDefault(r => r.ServiceType == typeof(T))
?? throw new InvalidOperationException(
$"You forgot to register {typeof(T).Name}. Please call: " +
$"container.Register<{typeof(T).Name}>(Lifestyle.Scope);");
}
/// <summary>
/// Gets the context.
/// </summary>
/// <value>
/// The context.
/// </value>
public T Context
{
get
{
DbContext dbContext = (T)this.producer.GetInstance();
//Dynamic proxies are used for change tracking and lazy loading
//if DbContext.Configuration.ProxyCreationEnabled is set to false, DbContext will not load child objects
//for some parent object unless Include method is called on parent object.
dbContext.Configuration.ProxyCreationEnabled = false;
return (T)dbContext;
}
}
}
Then the interface
public interface IDbContextProvider<out T> where T : DbContext
{
/// <summary>
/// Gets the context.
/// </summary>
/// <value>
/// The context.
/// </value>
T Context { get; }
}
I can call this one from service layer like
private readonly IDbContextProvider<MyDbContext> _baseContextProvider;
public MyService(IDbContextProvider<MyDbContext> baseContextProvider)
{
this._baseContextProvider = baseContextProvider;
}

dynamically updating connection string - MVC

My requirement is, on the first time loading the application i want to fetch information about connection string from a database and next time onward's connect using the new connection string (which is fetched from the db)
is this possible in .net.? The connection string is written in web.config file
do I need to restart IIS whenever the web.config changes?
I tried this:
public ActionResult Index()
{
UpdateSetting("test", "123");
UpdateConnectionString("testcon", "12345");
return View();
}
/// <summary>
/// Updates the setting.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void UpdateSetting(string key, string value)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
if (config.AppSettings.Settings[key] == null)
{
config.AppSettings.Settings.Add(key, value);
}
else
{
config.AppSettings.Settings[key].Value = value;
}
config.Save();
ConfigurationManager.RefreshSection("appSettings");
}
/// <summary>
/// Updates the connection string.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void UpdateConnectionString(string key, string value)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
if (config.ConnectionStrings.ConnectionStrings[key] == null)
{
config.ConnectionStrings.ConnectionStrings.Add(new ConnectionStringSettings(key, value));
}
else
{
config.ConnectionStrings.ConnectionStrings[key].ConnectionString = value;
}
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
}
This function will add a new connection string but is there any other method so that i don't want to restart the application?
The application setting is static and should not be modified in the runtime. I don't know why you have to store the connection in the config file, it doesn't make sense. Try another solution, update the setting by a script before start or store the setting in another or just retrieve every time.
There are multiple options to achieve this.
If you're using DI, you can register the connection string factory as a singleton, and then just try to get connection string wherever you'd like. It'll fetch it only once for the application.
Update your UpdateConnectionString method to cache the retrieved value in some static variable (not a great way to do it, though) and then, and check the cache before retrieving the value. If cache is not null, use its value.

Microsoft Bot Framework working with database results

I am trying to get my Dialog to work with my database.
If I have my dialog like this:
[Serializable]
public class QuestionDialog : IDialog<object>
{
/// <summary>
/// Start our response
/// </summary>
/// <param name="context">The current context</param>
/// <returns></returns>
public async Task StartAsync(IDialogContext context)
{
// Move to the next method
context.Wait(StepOneAsync);
}
/// <summary>
/// When our message is recieved we execute this delegate
/// </summary>
/// <param name="context">The current context</param>
/// <param name="result">The result object</param>
/// <returns></returns>
private async Task StepOneAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
// Get our activity
var activity = await result;
// Ask our first question
await context.PostAsync("hi");
// Get our answer
context.Done(this);
}
}
Everything works fine and I get my message as expected. I then changed it to this:
[Serializable]
public class QuestionDialog : IDialog<object>
{
// Private properties
private IList<QuestionGroup> _questionGroups;
/// <summary>
/// Start our response
/// </summary>
/// <param name="context">The current context</param>
/// <returns></returns>
public async Task StartAsync(IDialogContext context)
{
try
{
// Create our service
var questionGroupService = new QuestionGroupService(new UnitOfWork<DatabaseContext>());
// Add our question groups
this._questionGroups = await questionGroupService.ListAllAsync();
// Move to the next method
context.Wait(StepOneAsync);
} catch (Exception ex)
{
}
}
/// <summary>
/// When our message is recieved we execute this delegate
/// </summary>
/// <param name="context">The current context</param>
/// <param name="result">The result object</param>
/// <returns></returns>
private async Task StepOneAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
// Get our activity
var activity = await result;
// Ask our first question
await context.PostAsync("hi");
// Get our answer
context.Done(this);
}
}
And it doesn't go the the StepOneAsync method. Can anyone see anything glaringly obvious as to why this isn't working?
Make sure your QestionGroup model is marked as Serializable.
If you cannot make it serializable and you still want to reference it during your dialog, you need to go with one of the alternatives described in the "How can I reference non-serializable services from my C# dialogs?" section of the Bot Framework Technical FAQ.
The simplest one is to use the NonSerialized attribute in your field.
Alternatively, you can try using registering the Reflection Serialization Surrogate by adding it to the Autofac container. In your global.asax, try adding this code:
var builder = new ContainerBuilder();
builder.RegisterModule(new ReflectionSurrogateModule());
builder.Update(Conversation.Container);

How to set Connection String with Entity Framework

I am using EF6 with MySQL and have a Model that I will use for MULTIPLE Databases.
I would like to be able to set the connections settings in my Form.
How do I set the Connection String for my Model programatically?
you should use EntityConnectionFactory
Here is what you need.
public string CreateConnectionString(string BasicConnectionString)
{
//EntityConnectionFactory
var entityConnectionStringBuilder= new EntityConnectionStringBuilder();
entityConnectionStringBuilder.Provider = "Your Provicer here" //For me it is "System.Data.SqlClient";
entityConnectionStringBuilder.ProviderConnectionString = BasicConnectionString;
entityConnectionStringBuilder.Metadata = "res://*";
return entityConnectionStringBuilder.ToString();
}
Here is an sample usage
MyContext ctx = new MyContext(CreateConnectionString())
:: Update ::
As you are using DB first method, see the following image
when these two radio buttons are available, select the first one. Then you will be able to set the connection string of your model.
Here is how my context looks like (Though it is object context. But doesn't matter in context of this question)
public partial class DataContext : ObjectContext
{
#region Constructors
/// <summary>
/// Initializes a new DataContext object using the connection string found in the 'DataContext' section of the application configuration file.
/// </summary>
public DataContext() : base("name=DataContext", "DataContext")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
/// <summary>
/// Initialize a new DataContext object.
/// </summary>
public DataContext(string connectionString) : base(connectionString, "DataContext")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
/// <summary>
/// Initialize a new DataContext object.
/// </summary>
public DataContext(EntityConnection connection) : base(connection, "DataContext")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
#endregion
#region Partial Methods
partial void OnContextCreated();
#endregion
...
}
Update
Add the constructor you are looking for in a partial class outside of the auto-generated entity class:
public partial class WMSChennaiDEVEntities : DbContext
{
public WMSChennaiDEVEntities(string connectionstring)
: base(connectionstring)
{
}
}
This constructor is not included in EF 5/6 apparently to prevent us from accidentally passing a sql connection string when an entity connection string is desired.
you have to hardcode the connection string somewhere. The common place is app.config.
<connectionStrings>
<add name="Connection1" connectionString="Server=localhost\ServerInstance;Database=MyDB;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
Then in your Code First model, do the following:
public class MyContext : DbContext
{
public MyContext():base("Connection1")
{...}
You see that BCL db library and EF were all designed for such usage pattern.
Changing connection strings in UI is not desired in business applications since users won't change db location very often, unless you are developing a DB admin app or an installer.

Setting up C# solution with multiple projects using NLog in Visual Studio

My solution in Visual Studio 2012 currently contains two projects:
DLL
WPF application (which requires methods of the DLL)
Both, the DLL and the WPF application, use NLog for logging. Currently each project contains the NLog DLL itself.
Here is what I don't understand:
It seems unnecessary to me including the identical NLog DLL in each project.
The DLL however shall be reusable in other solutions, i.e. somehow the NLog DLL must be contained in the DLL project.
What would be an adequate way of setting up the Visual Studio solution and/or projects?
well you need the DLL in all projects where you use it and surely you need it deployed with the binaries of the executable (WPF application in your case) so that it can be found and used at runtime.
what I tend to do in all my projects is create a wrapper around the logging engine so that I do not need to reference and depend on specific third party logging APIs, like Log4Net or NLog, so I use my wrapper logging class everywhere and then I have a reference to the logging asembly only in the wrapper class's project and in the executable project to have the assembly deployed to the bin folder.
hope this helps ;-)
If your DLL is just a core library you plan on sharing among various projects, it may be wise to add an NLog reference and wrapper code to just that library, then make sure that any consumer application (such as your WPF project) has an NLog.config file associated with it.
Since you're using VS2012 I'm assuming you're also most likely working with .NET 4.5 which allows you to take advantage of the new caller info attributes. I've written the following code below for a basic NLog wrapper and believe it has the perfect balance of efficiency (doesn't use StackTrace) and usability.
using System;
using System.Runtime.CompilerServices;
using NLog;
namespace ProjectName.Core.Utilities
{
/// <summary>
/// Generic NLog wrapper.
/// </summary>
public static class Logger
{
/// <summary>
/// Gets or sets the enabled status of the logger.
/// </summary>
public static bool Enabled
{
get { return LogManager.IsLoggingEnabled(); }
set
{
if (value)
{
while (!Enabled) LogManager.EnableLogging();
}
else
{
while (Enabled) LogManager.DisableLogging();
}
}
}
/// <summary>
/// Writes the diagnostic message at the Trace level.
/// </summary>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
public static void Trace(string message, Exception exception = null,
[CallerFilePath] string callerPath = "",
[CallerMemberName] string callerMember = "",
[CallerLineNumber] int callerLine = 0)
{
Log(LogLevel.Trace, message, exception, callerPath, callerMember, callerLine);
}
/// <summary>
/// Writes the diagnostic message at the Debug level.
/// </summary>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
public static void Debug(string message, Exception exception = null,
[CallerFilePathAttribute] string callerPath = "",
[CallerMemberName] string callerMember = "",
[CallerLineNumber] int callerLine = 0)
{
Log(LogLevel.Debug, message, exception, callerPath, callerMember, callerLine);
}
/// <summary>
/// Writes the diagnostic message at the Info level.
/// </summary>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
public static void Info(string message, Exception exception = null,
[CallerFilePathAttribute] string callerPath = "",
[CallerMemberName] string callerMember = "",
[CallerLineNumber] int callerLine = 0)
{
Log(LogLevel.Info, message, exception, callerPath, callerMember, callerLine);
}
/// <summary>
/// Writes the diagnostic message at the Warn level.
/// </summary>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
public static void Warn(string message, Exception exception = null,
[CallerFilePathAttribute] string callerPath = "",
[CallerMemberName] string callerMember = "",
[CallerLineNumber] int callerLine = 0)
{
Log(LogLevel.Warn, message, exception, callerPath, callerMember, callerLine);
}
/// <summary>
/// Writes the diagnostic message at the Error level.
/// </summary>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
public static void Error(string message, Exception exception = null,
[CallerFilePathAttribute] string callerPath = "",
[CallerMemberName] string callerMember = "",
[CallerLineNumber] int callerLine = 0)
{
Log(LogLevel.Error, message, exception, callerPath, callerMember, callerLine);
}
/// <summary>
/// Writes the diagnostic message at the Fatal level.
/// </summary>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
public static void Fatal(string message, Exception exception = null,
[CallerFilePathAttribute] string callerPath = "",
[CallerMemberName] string callerMember = "",
[CallerLineNumber] int callerLine = 0)
{
Log(LogLevel.Fatal, message, exception, callerPath, callerMember, callerLine);
}
/// <summary>
/// Writes the specified diagnostic message.
/// </summary>
/// <param name="level"></param>
/// <param name="message"></param>
/// <param name="exception"></param>
/// <param name="callerPath"></param>
/// <param name="callerMember"></param>
/// <param name="callerLine"></param>
private static void Log(LogLevel level, string message, Exception exception = null, string callerPath = "", string callerMember = "", int callerLine = 0)
{
// get the source-file-specific logger
var logger = LogManager.GetLogger(callerPath);
// quit processing any further if not enabled for the requested logging level
if (!logger.IsEnabled(level)) return;
// log the event with caller information bound to it
var logEvent = new LogEventInfo(level, callerPath, message) {Exception = exception};
logEvent.Properties.Add("callerpath", callerPath);
logEvent.Properties.Add("callermember", callerMember);
logEvent.Properties.Add("callerline", callerLine);
logger.Log(logEvent);
}
}
}
Then try throwing this into the layout field of one of the targets in your NLog.config to grab the detailed caller information.
${event-context:item=callerpath}:${event-context:item=callermember}(${event-context:item=callerline})
You better abstract the use of your logging mechanism. I described this in this blog post, it's about log4net but is the same principle whatever framework you use. In any case, you need the log assembly in every project where you use it, but by abstracting it it's easy to replace it by something else (when testing for example). Logging is infrastructure, so you would put the interfaces and concrete implementation in an infrastructure project, and reference that one from the projects in which you want to log.

Categories

Resources