I am following the guidelines for configuring Serilog via C# instead of through a config file. This is for an Umbraco 8 application.
The guidelines specify that I need to inherit from UmbracoApplication and then override the GetLogger() method:
public class FineTuneLogging : UmbracoApplication
{
protected override ILogger GetLogger()
{
var loggerConfig = new LoggerConfiguration();
loggerConfig
.Enrich.WithProperty("MyProperty", "whatIWant")
.MinimalConfiguration()
.OutputDefaultTextFile(LogEventLevel.Error)
.OutputDefaultJsonFile(LogEventLevel.Information)
.ReadFromConfigFile()
.ReadFromUserConfigFile();
return new SerilogLogger(loggerConfig);
}
}
However, GetLogger() is not found in the inheritance tree.
Are the docs out of date or am I missing something?
You should be overriding GetRuntime
public class FineTuneLogging : UmbracoApplication
{
protected override IRuntime GetRuntime()
{
return new FineTuneLoggingRuntime(this);
}
}
public class FineTuneLoggingRuntime : WebRuntime
{
public FineTuneLoggingRuntime(UmbracoApplicationBase umbracoApplication) : base(umbracoApplication) { }
protected override ILogger GetLogger()
{
var loggerConfig = new LoggerConfiguration();
loggerConfig
.Enrich.WithProperty("MyProperty", "whatIWant")
.MinimalConfiguration()
.OutputDefaultTextFile(LogEventLevel.Error)
.OutputDefaultJsonFile(LogEventLevel.Information)
.ReadFromConfigFile()
.ReadFromUserConfigFile();
return new SerilogLogger(loggerConfig);
}
}
Related
I'm trying to create a viewmodel provider factory and I'm little bit lost. I've already added the required Nuget packages and my view models extend the AndroidViewModel type. Now, I'd like to create a factory that would use autofac to create the required view models from the OnCreate activitie's method. The creation call looks like this:
_viewModel = (ViewModelProviders.Of(this, _viewModelFactory)
.Get(Java.Lang.Class.FromType(typeof(MainActivityViewModel))) as JavaObjectWrapper<MainActivityViewModel>)
.Object;
Now, the factory:
public class ViewModelFactory : ViewModelProvider.AndroidViewModelFactory {
public ViewModelFactory(Application application) : base(application) {
}
public override Object Create(Class modelClass) {
// TODO: any way to get the .NET type that was passed here?
return base.Create(modelClass);
}
}
Can I retrieve the .NET type (MainActivityViewModel) from the Class instance that is passed into the Create method call (the type would be required to resolve it from the autofac container)? If there is, how can I do that?
Thanks.
This is how I do this with Unity, but this pattern can be used for passing anything through the ViewModel constructor:
The ViewModel itself
public class HomeViewModel : ViewModel
{
IUnityContainer _unityContainer;
public HomeViewModel(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
}
The HomeViewModelFactory (Default constructor required)
public class HomeViewModelFactory : Java.Lang.Object, ViewModelProvider.IFactory
{
IUnityContainer _unityContainer;
public HomeViewModelFactory()
{
}
public HomeViewModelFactory(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public Java.Lang.Object Create(Class p0)
{
return _unityContainer.Resolve<HomeViewModel>();
}
}
Usage in Fragment
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
var homeViewModelFactory = _unityContainer.Resolve<HomeViewModelFactory>();
_homeViewModel = ViewModelProviders.Of(this, homeViewModelFactory).Get(Java.Lang.Class.FromType(typeof(HomeViewModel))) as HomeViewModel;
}
I have an intranet application that uses the Windows username and passes that to a procedure to return data.
I'm using dependency injection, but I don't believe I have the method to get the username separated properly.
I'm trying to keep this secure by not passing in the username as a parameter, but I also want to be able to impersonate (or bypass my GetWindowsUser() method) and send in another username so I can test results for other users.
One idea I had for this was to set a session variable in another page with another (impersonated) username, then check if that session variable exists first before grabbing the actual user name, but I couldn't figure out how to access the session variable in the repository.
WEB API CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection using Unity.WebAPI NuGet Package
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage MyList()
{
try
{
return _dropDownDataRepository.MyList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private DatabaseEntities db = new DatabaseEntities();
public HttpResponseMessage MyList()
{
//(This should be separated somehow, right?)
//Create a new instance of the Utility class
Utility utility = new Utility();
//Grab the windowsUser from the method
var windowsUser = utility.GetWindowsUser();
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.myProcedure(windowsUser)
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
INTERFACE
public interface IDropDownDataRepository : IDisposable
{
HttpResponseMessage MyList();
}
UTILITY CLASS
public class Utility
{
public string GetWindowsUser()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
return windowsUser;
}
}
UPDATE 1
In addition to what Nikolai and Brendt posted below, the following is also needed to allow Web Api controllers work with the session state.
Accessing Session Using ASP.NET Web API
Abstract the Utility class and inject it into the repository.
Then you can stub or mock for testing.
public interface IUtility
{
string GetWindowsUser();
}
public class TestUtility : IUtility
{
public string GetWindowsUser()
{
return "TestUser";
}
}
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private IUtility _utility;
public DropDownDataRepository(IUtility utility)
{
_utility = utility;
}
}
EDIT
Also the repository should not return an HTTPResponseMessage type it should just return a List<T> of the domain model you're accessing.
i.e.
public List<Model> MyList()
{
//Grab the windowsUser from the method
var windowsUser = _utility.GetWindowsUser();
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.myProcedure(windowsUser)
select p).ToList();
return sourceQuery
}
Then move the JSON portion to the controller.
One idea I had for this was to set a session variable in another page
with another (impersonated) username, then check if that session
variable exists first before grabbing the actual user name, but I
couldn't figure out how to access the session variable in the
repository.
Potentially, if you add in a dependency to session, you need to isolate it, e.g.
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
// ... other fields
private ISession session;
public DropDownDataRepository(ISession session)
{
this.session = session;
}
public HttpResponseMessage MyList()
{
var myUserName = this.session.UserName;
// ... etc
With ISession being something like:
public interface ISession
{
string UserName { get; }
}
Implemented as:
public class MySession : ISession
{
public string UserName
{
get
{
// potentially do some validation and return a sensible default if not present in session
return HttpContext.Current.Session["UserName"].ToString();
}
}
}
Of course there is the potential to decouple this MySession class from HttpContext if desired.
With regards to this:
//(This should be separated somehow, right?)
//Create a new instance of the Utility class
Utility utility = new Utility();
Yes, anytime you create a new object you are tightly coupling them together, which will give you issues, for example, if you try to unit test it in isolation.
In this instance you could extract an IUtility interface from Utility:
public class Utility : IUtility
{
string GetWindowsUser();
}
Then:
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
// ... other fields
private IUtility utility;
public DropDownDataRepository(IUtility utility)
{
this.utility = utility;
// .... etc
Then you have removed the depenedency between Utility and DropDownDataRepository, and can substitute in another type or mock with ease.
I got a lot of help from Nikolai and Brent and got most of the way there with their posted answers, but ended up figuring out the complete answer on my own. The problems I was having were related to not being able to access session variables in a WebAPI. So, I'm sure there are cleaner solutions to this, but I definitely improved what I had and came up with the following code, which works.
This answer was needed to allow access to the session variable in Web Api - Accessing Session Using ASP.NET Web API
GLOBAL.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
UnityConfig.RegisterComponents();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
//Added to allow use of session state in Web API
protected void Application_PostAuthorizeRequest()
{
if (IsWebApiRequest())
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
//Added to allow use of session state in Web API
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
}
protected void Session_Start(Object sender, EventArgs e)
{
//Default set the session variable to none
Session["_impersonatedUser"] = "none";
}
protected void Session_End(Object sender, EventArgs e)
{
//Reset the session variable to blank
Session["_impersonatedUser"] = "";
}
}
UNITY.config
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IDropDownDataRepository, DropDownDataRepository>();
container.RegisterType<IUtilityRepository, UtilityRepository>();
container.RegisterType<ISessionRepository, SessionRepository>();
//MVC5
//Unity.MVC5 NuGet Package
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
//WEB API
//Unity.WebApi NuGet Package
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
WEB API CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection using Unity.WebAPI NuGet Package
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage MyList()
{
try
{
var sourceQuery = _dropDownDataRepository.MyList();
//JSON stuff moved to controller
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
protected override void Dispose(bool disposing)
{
_dropDownDataRepository.Dispose();
base.Dispose(disposing);
}
}
DROPDOWNDATA REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private DatabaseEntities db = new DatabaseEntities();
private IUtilityRepository _utilityRepository;
private ISessionRepository _sessionRepository;
//Dependency Injection of Utility and Session
public DropDownDataRepository(IUtilityRepository utilityRepository, ISessionRepository sessionRepository)
{
_utilityRepository = utilityRepository;
_sessionRepository = sessionRepository;
}
//Changed to a list here
public List<MyProcedure> MyList()
{
string windowsUser;
//Check the session variable to see if a user is being impersonated
string impersonatedUser = _sessionRepository.ImpersonatedUser;
//Grab the windowsUser from the Utility Repository
windowsUser = _utilityRepository.GetWindowsUser();
if (impersonatedUser != "none")
{
windowsUser = impersonatedUser;
}
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.MyProcedure(windowsUser)
select p).ToList();
return sourceQuery;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
DROPDOWNDATA INTERFACE
public interface IDropDownDataRepository : IDisposable
{
//Changed to list here
List<MyProcedure> MyList();
}
UTILITY REPOSITORY
public class UtilityRepository : IUtilityRepository
{
public string GetWindowsUser()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
return windowsUser;
}
}
UTILITY INTERFACE
public interface IUtilityRepository
{
string GetWindowsUser();
}
SESSION REPOSITORY
public class SessionRepository : ISessionRepository
{
public string ImpersonatedUser
{
get
{
return HttpContext.Current.Session["_impersonatedUser"].ToString();
}
}
}
SESSION INTERFACE
public interface ISessionRepository
{
string ImpersonatedUser { get; }
}
How Can I add BuildMessage(s) in custom BuildActivity?
[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class InvokeDotNetReactor : CodeActivity
{
[RequiredArgument]
public InArgument<string> SourcesDirectory { get; set; }
protected override void Execute(CodeActivityContext context)
{
...
BuildMessage bm = new BuildMessage()
{
Importance = BuildMessageImportance.High,
Message = "Hello From Custom TFS Build Activity"
};
}
}
}
For WorklowActivity there is a special WorkflowInvoker...
Thank's a lot.
Logging in a CodeActivity can be done using the CodeActivityContext.
Example:
protected override void Execute(CodeActivityContext context)
{
context.TrackBuildMessage("Hello from Custom TFS Build Activity", BuildMessageImportance.High);
}
TrackBuildMessage is an Extension method which can be found in namespace: Microsoft.TeamFoundation.Build.Workflow.Activities
I have successfully setup a simple mvc application that lists teams. I'm using Ninject to inject the appropriate repository depending on the controller (thanks to stack overflow ;). All looks good, except that the repository code looks exactly the same. And I know that's wrong. So my TeamRepository has two classes (for now).
public class SwimTeamRepository : ITeamRepository<SwimTeam>
{
private readonly Table<SwimTeam> _teamTable;
public SwimTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SwimTeam>());
}
public IQueryable<SwimTeam> Team
{
get { return _teamTable; }
}
}
public class SoccerTeamRepository : ITeamRepository<SoccerTeam>
{
private readonly Table<SoccerTeam> _teamTable;
public SoccerTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SoccerTeam>());
}
public IQueryable<SoccerTeam> Team
{
get { return _teamTable; }
}
}
They look exactly the same except for the Class and Table name, so clearly I need to re-factor this. What would be the best approach here? Singleton? Factory Method?
Thanks in advance!
You could use generics:
public interface ITeamRepository<T>
{
}
public class TeamRepository<TTeam> : ITeamRepository<TTeam>
where TTeam : Team
{
private readonly Table<TTeam> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<TTeam>());
}
public IQueryable<TTeam> Team
{
get { return _teamTable; }
}
}
public class Team
{
}
public class SwimTeam : Team
{
}
Then use it like so...
public void MyMethod()
{
var repository = new TeamRepository<SwimTeam>();
}
...and set up your IoC container w/ Ninject like so...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<ITeamRepository<SwimTeam>>
.To<TeamRepository<SwimTeam>>();
}
}
public void MyMethod()
{
var repository = kernel.Get<ITeamRepository<SwimTeam>>();
}
If you want to get REAL generic and have a single repository for ALL of your mapped classes, you can do something like this:
public interface IRepository
{
IQueryable<T> Get<T>() where T : class, new();
}
public class Repository : IRepository, IDisposable
{
private DataContext _dataContext;
public Repository(string connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IQueryable<T> Get<T>()
where T : class, new()
{
return _dataContext.GetTable<T>().AsQueryable();
}
public void Dispose()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
...which you could call like so (after setting up your Ninject container)...
using (var repository = kernel.Get<IRepository>())
{
var swimTeam = repository.Get<SwimTeam>();
}
Since Ninject takes care of the life-cycle management of your objects, you don't HAVE to wrap the repository in a using statement. In fact, you don't want to use a using statement there at all if you plan to use the repository more than once within the scope of its lifetime. Ninject will automatically dispose of it when it's life-cycle ends.
Here's a good article by Rob Conery on using this kind of technique to reduce the friction of using different ORMs.
EDIT by keeg:
I Think
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : Team {}
Should be
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : class {}
Please correct if I'm wrong.
Is this what you want?
public class TeamRepository : ITeamRepository<T>
{
private readonly Table<T> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<T>());
}
public IQueryable<T> Team
{
get { return _teamTable; }
}
}
I'm trying to work with NInject in my MVC 3 application, and i have one question.
Interface
public interface ITalesRepository
{
IEnumerable<Tale> GetAllTales();
}
Repository
public class TalesRepository : ITalesRepository
{
private FairyTalesMVC3DataContext _dataContext;
public TalesRepository(FairyTalesMVC3DataContext dataContext)
{
_dataContext = dataContext;
}
public IEnumerable<Tale> GetAllTales()
{
return _dataContext.Tales.OrderBy(c => c.NameAn);
}
}
Home controller
public class HomeController : Controller
{
private readonly ITalesRepository _talesRepository;
public HomeController(ITalesRepository talesRepository)
{
_talesRepository = talesRepository;
}
public ActionResult Index()
{
ViewBag.Tales = _talesRepository.GetAllTales();
return View();
}
}
So, i need to initialize my TalesRepository with DataContext, and now it is so:
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
kernel.Bind<ITalesRepository>().To<TalesRepository>().WithConstructorArgument("dataContext", new FairyTalesMVC3DataContext(ConfigurationManager.ConnectionStrings["dbFairyTalesConnectionString"].ConnectionString));
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
So, my question, is it ok or something wrong?
First of all:
public IEnumerable<Tale> GetAllTales()
{
return _dataContext.Tales.OrderBy(c => c.NameAn);
}
I would add .ToList() to the end. Else you'll get data layer exceptions in your presentation layer which is not fine.
Next, I would recommend that you switch to ViewModels instead of using ViewBag. It's a lot easier to prevent that logic leaks into the views if you are using ViewModels. Since you can add the logic to the ViewModel and thus get the same behaviour in all views using the model.
Your application should inherit from NinjectHttpApplication. It registers dependency resolver, so you don't have to do it.
You should also override CreateKernel in application class and register your own module with bindings:
public class MvcApplication : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
return new StandardKernel(new INinjectModule[] {new MvcModule()});
}
}
public class MvcModule : NinjectModule
{
public override void Load()
{
Bind<ITalesRepository>().To<TalesRepository>();
Bind<FairyTalesMVC3DataContext>().To<FairyTalesMVC3DataContext>().InRequestScope();
}
}