I'm using bltoolkit in my ASP.Net application , I use repository pattern to manage my data access layer. foreach operation i open a new DbManager . I cannot find a way to open and dispose the DbManager Object per request or session . any ideas
IMHO, best way of usage:
public IEnumerable<int> GetMyTableIds()
{
using (var dbManager = new DbManager("database"))
{
return dbManager.GetTable<MyTable>()
.Select(table => table.Id)
.ToArray();
}
}
Call of
new DbManager("database")
can be extracted to factory.
Or you may use thread static variables
static class DbManagerContainer
{
[ThreadStatic]
public static DbManager DbManager;
}
public void Request_Start()
{
DbManagerContainer.DbManager = new DbManager("database");
}
public void Request_End()
{
if (DbManagerContainer.DbManager == null)
{
//Write warn to log. This is not normal case.
}
else
{
DbManagerContainer.DbManager.Dispose();
DbManagerContainer.DbManager = null;
}
}
Related
I have a function app connected with an application insights instance.
When I look at the requests on application insights, all entries have a resultCode of 0, regardless of whether it was successful or not. How can I have the resultCode showing properly?
If I get it correctly, my function app is running at the version "3.0.14916.0".
Here is my startup:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging(loggingBuilder =>
{
var key = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
loggingBuilder.AddApplicationInsights(key);
});
builder.Services.AddSingleton(sp =>
{
var key = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
return new TelemetryConfiguration(key);
});
(...)
}
}
Edit 1:
In the comments it was asked why I am adding logging in Startup. I do it because, as far as I could verify, ILogger < MyClass > only logs to AI if I add logging in Startup.
Following is an example of an injected class. Note that this class is also used in other projects.
public class CosmosDbService : ICosmosDbService
{
private readonly IDocumentClient _documentClient;
private readonly ILogger _logger;
public CosmosDbService(IDocumentClient documentClient, ILogger<CosmosDbService> logger)
{
_logger = logger;
_documentClient = documentClient;
}
public async Task<UserData> GetUserAsync()
{
try
{
// Getting user here
// (...)
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching user.");
throw;
}
}
}
This class is injected as:
builder.Services.AddSingleton<IDocumentClient>(sp =>
{
// This does not really matter for this question
var configuration = sp.GetService<IConfiguration>();
var connectionString = configuration.GetValue<string>("COSMOS_DB_CONNECTION");
var cosmosDbConnectionString = new CosmosDbConnectionString(connectionString);
return new DocumentClient(cosmosDbConnectionString.ServiceEndpoint, cosmosDbConnectionString.AuthKey);
});
builder.Services.AddSingleton<ICosmosDbService, CosmosDbService>();
This answer from #PeterBons helped me fixing the wrong resultCode as well.
Basically I was importing the wrong package: Microsoft.Extensions.Logging.ApplicationInsights
I changed it to Microsoft.Azure.WebJobs.Logging.ApplicationInsights and removed the code in Startup. Now I got the resultCode properly filled in again.
I have a following problem. I register my components and initialize them in Unity like this (example is for a Console application):
public class SharePointBootstrapper : UnityBootstrapper
{
...
public object Initialize(Type type, object parameter) =>
Container.Resolve(type,
new DependencyOverride<IClientContext>(Container.Resolve<IClientContext>(parameter.ToString())),
new DependencyOverride<ITenantRepository>(Container.Resolve<ITenantRepository>(parameter.ToString())));
public void RegisterComponents()
{
Container
.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString())
.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString())
.RegisterType<ITenantRepository, DocumentDbTenantRepository>(SharePointClientContext.Online.ToString())
.RegisterType<ITenantRepository, JsonTenantRepository>(SharePointClientContext.OnPremise.ToString());
}
}
public enum SharePointClientContext
{
Online,
OnPremise
}
class Program
{
static void Main(string[] args)
{
...
bootstrap.RegisterComponents();
var bla = bootstrap.Initialize(typeof(ISharePointManager), SharePointClientContext.Online);
}
}
So, I register my components in MVC, WCF, Console etc. once with RegisterComponents() and initialize them with Initialize().
My question is, if I want to initialize specific named registration at runtime, from e.g. user input, can it be done otherwise as the code presented (with InjectionFactory or similar)?
This code works fine, but I'm not happy with its implementation. I have a feeling that it could be written in RegisterComponents() instead of Initialize() so that it accepts a parameter of some type, but I don't know how to do it.
Or, is maybe my whole concept wrong? If so, what would you suggest? I need to resolve named registration from a parameter that is only known at runtime, regardless of the technology (MVC, WCF, Console, ...).
Thanks!
Instead of doing different registrations, I would do different resolves.
Let's say that you need to inject IClientContext, but you want different implementations depending on a runtime parameter.
I wrote a similiar answer here. Instead of injecting IClientContext, you could inject IClientContextFactory, which would be responsible for returning the correct IClientContext. It's called Strategy Pattern.
public interface IClientContextFactory
{
string Context { get; } // Add context to the interface.
}
public class SharePointOnlineClientContext : IClientContextFactory
{
public string Context
{
get
{
return SharePointClientContext.Online.ToString();
}
}
}
// Factory for resolving IClientContext.
public class ClientContextFactory : IClientContextFactory
{
public IEnumerable<IClientContext> _clientContexts;
public Factory(IClientContext[] clientContexts)
{
_clientContexts = clientContexts;
}
public IClientContext GetClientContext(string parameter)
{
IClientContext clientContext = _clientContexts.FirstOrDefault(x => x.Context == parameter);
return clientContext;
}
}
Register them all, just as you did. But instead of injecting IClientContext you inject IClientContextFactor.
There also another solution where you use a Func-factory. Look at option 3, in this answer. One may argue that this is a wrapper for the service locator-pattern, but I'll leave that discussion for another time.
public class ClientContextFactory : IClientContextFactory
{
private readonly Func<string, IClientContext> _createFunc;
public Factory(Func<string, IClientContext> createFunc)
{
_createFunc = createFunc;
}
public IClientContext CreateClientContext(string writesTo)
{
return _createFunc(writesTo);
}
}
And use named registrations:
container.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString());
container.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString());
container.RegisterType<IFactory, Factory>(
new ContainerControlledLifetimeManager(), // Or any other lifetimemanager.
new InjectionConstructor(
new Func<string, IClientContext>(
context => container.Resolve<IClientContext>(context));
Usage:
public class MyService
{
public MyService(IClientContextFactory clientContextFactory)
{
_clientContextFactory = clientContextFactory;
}
public void DoStuff();
{
var myContext = SharePointClientContext.Online.ToString();
IClientContextclientContext = _clientContextFactory.CreateClientContext(myContext);
}
}
I have the following HttpModule that I wanted to unit test. Problem is I am not allowed to change the access modifiers/static as they need to be as it is. I was wondering what would be the best method to test the following module. I am still pretty new in testing stuff and mainly looking for tips on testing strategy and in general testing HttpModules. Just for clarification, I am just trying to grab each requested URL(only .aspx pages) and checking if the requested url has permission (for specific users in our Intranet). So far it feels like I can't really test this module(from productive perspective).
public class PageAccessPermissionCheckerModule : IHttpModule
{
[Inject]
public IIntranetSitemapProvider SitemapProvider { get; set; }
[Inject]
public IIntranetSitemapPermissionProvider PermissionProvider { get; set; }
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += ValidatePage;
}
private void EnsureInjected()
{
if (PermissionProvider == null)
KernelContainer.Inject(this);
}
private void ValidatePage(object sender, EventArgs e)
{
EnsureInjected();
var context = HttpContext.Current ?? ((HttpApplication)sender).Context;
var pageExtension = VirtualPathUtility.GetExtension(context.Request.Url.AbsolutePath);
if (context.Session == null || pageExtension != ".aspx") return;
if (!UserHasPermission(context))
{
KernelContainer.Get<UrlProvider>().RedirectToPageDenied("Access denied: " + context.Request.Url);
}
}
private bool UserHasPermission(HttpContext context)
{
var permissionCode = FindPermissionCode(SitemapProvider.GetNodes(), context.Request.Url.PathAndQuery);
return PermissionProvider.UserHasPermission(permissionCode);
}
private static string FindPermissionCode(IEnumerable<SitemapNode> nodes, string requestedUrl)
{
var matchingNode = nodes.FirstOrDefault(x => ComparePaths(x.SiteURL, requestedUrl));
if (matchingNode != null)
return matchingNode.PermissionCode;
foreach(var node in nodes)
{
var code = FindPermissionCode(node.ChildNodes, requestedUrl);
if (!string.IsNullOrEmpty(code))
return code;
}
return null;
}
public void Dispose() { }
}
For other people still looking there is this post which explains a way to do it
Original page was deleted, you can get to the article here:
https://web.archive.org/web/20151219105430/http://weblogs.asp.net/rashid/unit-testable-httpmodule-and-httphandler
Testing HttpHandlers can be tricky. I would recommend you create a second library and place the functionality you want to test there. This would also get you a better separation of concerns.
I'm trying to convert my data layer from Linq2Sql to nHibernate. I think Xml the configuration in nHibernate is pretty backwards so I'm using Fluent.
I've managed to get fluent, add in a repository pattern and unit of work pattern, and my unit tests are looking good.
However now as I'm plugging it into my services layer I'm noticing that each time I run my app the database gets recreated.
I am guessing this is down to my SessionProvider code, I'm not sure of all the extensions I'm using. Can someone shed some light on how to stop this from happening?
public sealed class SessionProvider
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory CreateSessionFactory()
{
try
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ConnectionString(Properties.Settings.Default.DBConnection)
.Cache(c => c
.UseQueryCache()
.ProviderClass<HashtableCacheProvider>())
//.ProxyFactoryFactory("NHibernate.ByteCode.Castle.ProxyFactoryFactory,NHiber nate.ByteCode.Castle")
.ShowSql())
.Mappings(m=>m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
}
public static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
_sessionFactory = CreateSessionFactory();
}
return _sessionFactory;
}
}
public static ISession GetSession()
{
return SessionFactory.OpenSession();
}
private static void BuildSchema(Configuration config)
{
// this NHibernate tool takes a configuration (with mapping info in)
// and exports a database schema from it
new SchemaExport(config).Create(false, true);
}
}
Remove this line
.ExposeConfiguration(BuildSchema)
Read more about new SchemaExport(config).Create(false, true); here
Actually last argument is all about to create database.
I'm starting a web application that contains the following projects:
Booking.Web
Booking.Services
Booking.DataObjects
Booking.Data
I'm using the repository pattern in my data project only. All services will be the same, no matter what happens. However, if a customer wants to use Access, it will use a different data repository than if the customer wants to use SQL Server.
I have StructureMap, and want to be able to do the following:
Web project is unaffected. It's a web forms application that will only know about the services project and the dataobjects project.
When a service is called, it will use StructureMap (by looking up the bootstrapper.cs file) to see which data repository to use.
An example of a services class is the error logging class:
public class ErrorLog : IErrorLog
{
ILogging logger;
public ErrorLog()
{
}
public ErrorLog(ILogging logger)
{
this.logger = logger;
}
public void AddToLog(string errorMessage)
{
try
{
AddToDatabaseLog(errorMessage);
}
catch (Exception ex)
{
AddToFileLog(ex.Message);
}
finally
{
AddToFileLog(errorMessage);
}
}
private void AddToDatabaseLog(string errorMessage)
{
ErrorObject error =
new ErrorObject
{
ErrorDateTime = DateTime.Now,
ErrorMessage = errorMessage
};
logger.Insert(error);
}
private void AddToFileLog(string errorMessage)
{
// TODO: Take this value from the web.config instead of hard coding it
TextWriter writer = new StreamWriter(#"E:\Work\Booking\Booking\Booking.Web\Logs\ErrorLog.txt", true);
writer.WriteLine(DateTime.Now.ToString() + " ---------- " + errorMessage);
writer.Close();
}
}
I want to be able to call this service from my web project, without defining which repository to use for the data access. My boostrapper.cs file in the services project is defined as:
public class Bootstrapper
{
public static void ConfigureStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry(new ServiceRegistry());
}
);
}
public class ServiceRegistry : Registry
{
protected override void configure()
{
ForRequestedType<IErrorLog>().TheDefaultIsConcreteType<Booking.Services.Logging.ErrorLog>();
ForRequestedType<ILogging>().TheDefaultIsConcreteType<SqlServerLoggingProvider>();
}
}
}
What else do I need to get this to work? When I defined a test, the ILogger object was null.
Perhaps some details on how you are calling this code from a test would be useful.
My understanding is that you need to ensure that the ConfigureStructureMap call has been made early in the applications life (e.g. in the Global.asax in a web project).
After that you would be calling for instances of IErrorLog using something like:
IErrorLog log = StructureMap.ObjectFactory.GetNamedInstance<IErrorLog>();