I would like to use the MiniProfiler for my MVC3 application, so I followed Scott Hanselman's blog post
My Global.asax.cs file has the necessary changes like in the source's MVC sample.
But I would like to measure a particular call in my controller.
So I put this code in controller:
if (Request.IsLocal)
{
var profiler = MiniProfiler.Current;
using (profiler.Step("SelectUserDetail Function"))
{
user = UserService.SelectUserDetail(userId);
}
}
I suspect my code will never in production environment as I'm wrapping this block in a Request.IsLocal check.
How can I do this check for only for local call or if I run in debug mode? At any case, it should execute the user = UserService.SelectUserDetail(userId) statement.
If I understand your question correctly, you're only wanting to call MiniProfiler's .Step() extension method when running locally (or debugging), correct?
If so, this kinda defeats the purpose of MiniProfiler, which is to have all this instrumentation available for production code, without impacting production.
I'm confident you can simply do this in your code:
using (MiniProfiler.Current.Step("SelectUserDetail Function"))
{
user = UserService.SelectUserDetail(userId);
}
and it will have virtually no impact on your app; we literally do this hundreds of times in our code here on Stack Overflow without issue (as well as every single database query).
You should only need to have your checks when a new request comes in:
protected void Application_BeginRequest()
{
if (Request.IsLocal) { MiniProfiler.Start(); }
}
When you're running in production, any calls to MiniProfiler.Current.Step() will return nothing, since the profiler is null (the beauty of extension methods).
If you still want to prevent any using statements from appearing in your production code, you should familiarize yourself with preprocessor directives. See this question, as well. However, I would strongly advise against them for this purpose, as it isn't necessary.
I usually create something like DebugHelper static class and define there:
public static class DebugHelper
{
private static bool? _isDebugEnabled = false;
public static bool IsDebug
{
get
{
if (!_isDebugEnabled.HasValue)
{
_isDebugEnabled = false;
#if DEBUG
_isDebugEnabled = true;
#endif
}
//may be extra rules like check for some debug key in HttpContext.Current etc.
return _isDebugEnabled.Value;
}
set { _isDebugEnabled = value; }
}
public static bool IsDevEnvironment
{
get
{
string environment = settingsService.GetSettingByKey<string>("environment");
return environment == "dev";
}
}
public static bool IsTestEnvironment
{
get
{
string environment = settingsService.GetSettingByKey<string>("environment");
return environment == "test";
}
}
DebuHelper allows me easily switch on/switch off debug mode, logging, tracing etc. add extra output or whatever for dev and test environment
Related
I'm using mapstruct in my project, and recently went to add some 'mutation analysis' using pitest.
The problem I have is that a mutant is created on some generated code, and I cannot fix my test to kill it since this is concerning null check generated by mapstruct, that are unreacheable.
ie, if I have the following mapper :
#Mapper
public abstract class MyMapper {
#Mapping(source= "someInnerObject.field", target="someField")
public abstract Bar toBar(Foo foo);
}
Mapstruck will generate something like this :
public class MyMapperImpl extends MyMapper {
#Override
public Bar toBar(Foo foo) {
if(foo == null) {
return null; // reacheable code, all is fine here.
}
Bar bar = new Bar();
bar.setSomeField(fooSomeField(foo))
return bar;
}
private String fooSomeField(Foo foo) {
if (foo == null) {
return null; // Unreacheable code, already tested in public method.
}
SomeInnerObject innerObject = foo.getSomeInnerObject()
if(innerObject == null) {
return null; // reacheable code, no problem here
}
String field = o.getField();
if(field == null) {
return null; // reacheable, no problem here.
}
return field;
}
}
As we can see, mapstruct generates a null check that is unreacheable, making it impossible to cover those line in test. The mutation analyser tries to return "" instead of null on the unreacheable line, and therefore, the mutant is never detected by my tests. This leads makes it impossible to get 100% code coverage and 100% mutation coverage.
I don't think excluding this generated code from the coverage or the mutation analysis would be a good choice, since the generated code reflect behavior that is coded as annotations in the mapper : So we would like to make sure these behaviors are correctly covered in tests.
Do someone here had the same problem, or any suggestion ?
I tried many different mapper config to get rid of the unreacheable line without success (unless I just disable all null checks, which would change my application logic).
The way MapStruct generates code doesn't allow us to skip the null check in the private method.
You can try raising an issue in the MapStruct project. However, I am not sure that it is worth spending time on skipping this null check. The JIT will in any case remove that check during runtime.
The topic about 100% code coverage and 100% mutation coverage is a topic for discussion that will lead to closing this question.
what is the best way to capture page views by person without slowing down performance on the site. I see that stackoverflow show page views all over the place. Are they doing an insert into a db everytime i click on a page?
In asp.net-mvc, Is there any recommended way to track page view per user (my site has a login screen) so i can review which pages people are going to and how often
First off.. if what you really care about is how are customers using my site then you most likely want to look into Google Analytics or a similar service.
But if you want a quick and dirty page view record and you are using ASP.Net MVC 3 then as Chris Fulstow mentioned you're going to want to use a mix of global action filters and caching. Here is an example.
PageViewAttribute.cs
public class PageViewAttribute : ActionFilterAttribute
{
private static readonly TimeSpan pageViewDumpToDatabaseTimeSpan = new TimeSpan(0, 0, 10);
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var calledMethod = string.Format("{0} -> {1}",
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
filterContext.ActionDescriptor.ActionName);
var cacheKey = string.Format("PV-{0}", calledMethod);
var cachedResult = HttpRuntime.Cache[cacheKey];
if(cachedResult == null)
{
HttpRuntime.Cache.Insert(cacheKey, new PageViewValue(), null, DateTime.Now.Add(pageViewDumpToDatabaseTimeSpan) , Cache.NoSlidingExpiration, CacheItemPriority.Default,
onRemove);
}
else
{
var currentValue = (PageViewValue) cachedResult;
currentValue.Value++;
}
}
private static void onRemove(string key, object value, CacheItemRemovedReason reason)
{
if (!key.StartsWith("PV-"))
{
return;
}
// write out the value to the database
}
// Used to get around weird cache behavior with value types
public class PageViewValue
{
public PageViewValue()
{
Value = 1;
}
public int Value { get; set; }
}
}
And in your Global.asax.cs
public class MvcApplication : HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new PageViewAttribute());
}
}
For pre-ASP.Net MVC 3 ONLY you are going to have to apply the same attribute manually to all of your actions.
[PageView]
public ActionResult CallOne()
{
}
[PageView]
public ActionResult CallTwo()
{
}
The best way would probably be a global action filter that intercepts requests to all actions on all controllers, then increments a counter in the database for the current user and page. To save hitting the database too hard, you could cache these values and invalidate them every few minutes, depending on how much traffic you're dealing with.
We use the open source Piwik: http://piwik.org/, which is setup on it's own server. One line of Javascript in the _Layout page makes a call to Piwik after the page has loaded (put the JS at the end) and does not affect page load performance at all.
In addition to just counts, you'll get a ton of info about where your users are coming from, browser, screen resolutions, installed plugins. Plus you can track conversions and use the same tool to track marketing campaigns, etc.
<soapbox>
I cannot think of a situation where you'd be better off implementing this in MVC or in your web app in general. This stuff simply does not belong in your web app and is a meta-concern that should be separated out. This approach has enabled us to track analytics for all of our apps (32 of them: mvc 2/3, webforms, php...) in a unified manner.
If you really don't want to use another tool for this purpose, I would recommend tapping into your IIS log and getting your stats from there. Again, to get any real decision making power out of it, you'll need to put a good analyzer on it. I recommend Splunk: http://www.splunk.com/
</soapbox>
I wanted to post an updated version of Shane's answer for those who are interested. Some things to consider:
You have to set the action attribute up as a service when decorating your
methods using syntax like the following :
[ServiceFilter(typeof(PageViewAttribute))]
As far as I can tell, HttpRuntime.Cache.Insert isn't a thing in .NET Core, so I used a simple implementation of IMemoryCache (You may need to add this line to your startup.cs in order to use the interface):
services.AddMemoryCache();
Because we are injecting IMemoryCache into a class that is not a controller, we need to register our attribute as a service in startup.cs, like so:
services.AddScoped<[PageViewAttribute]>(); - without brackets!
Whatever object you return when creating a cacheKey will be assigned to the 'value' parameter of the OnRemove method.
Below is the code.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controllerActionDescriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;
var arguments = filterContext.ActionArguments;
ActionId = arguments["id"].ToString();
var calledMethod = string.Format("{0} -> {1}",
controllerActionDescriptor.ControllerName,
controllerActionDescriptor.ActionName);
var cacheKey = string.Format("PV-{0}", calledMethod);
var cachedResult = _memoryCache.Get(cacheKey);
if (cachedResult == null)
{
//Get cacheKey if found, if not create cache key with following settings
_memoryCache.GetOrCreate(cacheKey, cacheKey =>
{
cacheKey.AbsoluteExpirationRelativeToNow
= pageViewDumpToDatabaseTimeSpan;
cacheKey.SetValue(1);
cacheKey.RegisterPostEvictionCallback(onRemove);
return cacheKey.Value;
});
}
else
{
_memoryCache.Get(cacheKey);
}
}
//Called when Memory entry is removed
private void onRemove(object key, object value, EvictionReason reason, object state)
{
if (!key.ToString().StartsWith("PV-"))
{
return;
}
// write out the value to the database
SaveToDataBase(key.ToString(), (int)value);
}
As a point of reference, this was done for a .NET Core 5 MVC App.
Regards.
I have a task that runs in a different thread and requires the session. I've done:
public GenerateDocList(LLStatistics.DocLists.DocList docs)
{
this.docs = docs;
context = HttpContext.Current;
}
and
public void StartTask()
{
//this code runs in a separate thread
HttpContext.Current = context;
/* rest of the code */
}
Now the thread has knowledge of the session and it works for a while but at some point in my loop HttpContext.Current.Session becomes null. Any ideas what can I do about this?
public static LLDAC.DAL.DBCTX LLDB
{
get
{
LLDAC.DAL.DBCTX currentUserDBContext = HttpContext.Current.Session["LLDBContext"] as LLDAC.DAL.DBCTX;
if (currentUserDBContext == null)
{
currentUserDBContext = new LLDAC.DAL.DBCTX();
HttpContext.Current.Session.Add("LLDBContext", currentUserDBContext);//this works only for a few loop iterations
}
return currentUserDBContext;
}
}
In general, this is a very fragile pattern for a multi-threaded operation. Long-running tasks (which I assume this is) are best suited to instance methods in a class rather than static methods such that the class can maintain any dependent objects. Also, since the session state is not thread safe and can span multiple requests you are getting into some very risky business by cashing your DB context in the session at all.
If you are convinced this is best done with static methods and stored in the session, you may be able to do something like this:
public static HttpSessionState MySession { get; set; }
public GenerateDocList(LLStatistics.DocLists.DocList docs)
{
this.docs = docs;
MySession = HttpContext.Current.Session;
}
Then:
public static LLDAC.DAL.DBCTX LLDB
{
get
{
LLDAC.DAL.DBCTX currentUserDBContext = MySession["LLDBContext"] as LLDAC.DAL.DBCTX;
if (currentUserDBContext == null)
{
currentUserDBContext = new LLDAC.DAL.DBCTX();
if (MySession == null)
{
thow new InvalidOperaionException("MySession is null");
}
MySession.Add("LLDBContext", currentUserDBContext);
}
return currentUserDBContext;
}
}
Note that you could still run into issues with the session since other threads could still modify the session.
A better solution would probably look something like this:
public class DocListGenerator : IDisposable
{
public LLDAC.DAL.DBCTX LLDB { get; private set; }
public DocListGenerator()
{
LLDB = new LLDAC.DAL.DBCTX();
}
public void GenerateList()
{
// Put loop here.
}
public void Dispose()
{
if (LLDB != null)
{
LLDB.Dispose();
}
}
}
Then your calling code looks like this:
public void StartTask()
{
using (DocListGenerator generator = new DocListGenerator()
{
generator.GenerateList();
}
}
If you really want to cache something, you could cache your instance like this:
HttpContext.Current.Sesssion.Add("ListGenerator", generator);
However, I still don't think that is a particularly good idea since your context could still be disposed or otherwise altered by a different thread.
Using anything related to the HttpContext.Current on anything besides the main Request thread is generally going to get you into trouble in ASP.net.
The HttpContext is actually backed on a thread belonging to a Thread Pool and the thread may very well get reused on another request.
This is actually a common issue with using the new Async/Await keywords in ASP.net as well.
In order to help you, it would help to know why you're attempting this in the first place?
Is this a single server or a web farm with multiple load balanced servers?
Are you hosting it yourself, or is it the site hosted by a provider?
What is the SessionState implementation (SQL Server, State Server, In-Process, or something custom like MemCached, Redis, etc...)
What version of ASP .net?
Why are you starting a new thread instead of just doing the processing on the request thread?
If you really can't (or shouldn't) use session. Then you could use something like a correlation ID.
Guid correlationID = Guid.NewGuid();
HttpContext.Current.Session["DocListID"] = correlationID;
DocList.GoOffAndGenerateSomeStuffOnANewThread(correlationID);
... when process is done, store the results somewhere using the specified ID
// Serialize the result to SQL server, the file system, cache...
DocList.StoreResultsSomewhereUnderID();
... later on
DocList.CheckForResultsUnderID(HttpContext.Current.Session["DocListID"]);
What is the best/standard way to put common variables and functions in Zend framework 2 (with doctrine), to be used across all the modules, specifically their controllers.
I read somewhere that our controllers should extend another controller (like AppCommonController) which, in turn, extends AbstractActionController. The AppCommonController will then define the common variables and functions that we can access in any controller that extends it.
Is there a better/standard way to do this?
---Updated---
Say for e.g., I want to check the current mode of my site (test or live) in most of my controllers (across different modules), and accordingly want to do the necessary in the actions.
I write following in some controller:
private $__currentMode = '';
public function __construct()
{
//following will be set to Live or Test depending on a session value
$this->setCurrentMode('Live');
}
public function setCurrentMode($mode)
{
$this->__currentMode = $mode;
}
public function getCurrentMode()
{
return $this->__currentMode;
}
I believe it is a bad idea to put above code in all the controllers where I need to check the current mode.
So I want to put it (both the currentMode property and getter/setter functions) at some place from where I can access them in all the controllers wherever needed.
Seems like this is what controller plugins are there for
First create a controller plugin...
namespace Application\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class MyModeHelper extends AbstractPlugin
{
protected $mode;
public function __construct($mode)
{
$this->mode = $mode;
}
public function getMode()
{
return $this->mode;
}
}
Then tell the controller manager about it in Module.php using the getControllerPluginConfig() method
// in Application/Module.php
public function getControllerPluginConfig()
{
return array(
'factories' => array(
'myModeHelper' => function($sm) {
// get mode from environment
$mode = 'live';
return new Controller\Plugin\MyModeHelper($mode);
}
)
); //fixed syntax error
}
}
Plugin should now be available any time you call it in a controller
// in your controllers
public function indexAction()
{
if ($this->myModeHelper()->getMode() == 'live') {
// do live stuff
} else {
// do test stuff
}
return new ViewModel();
}
Well, heavily depends on the functions.
First of: variables would probably best placed inside configuration. From there on they are accessible anywhere a ServiceLocator is present.
As far as functions are concerned, it heavily depends on what the functions do. Are they some sort of ControllerLogic? Then your approach Mymodule\Stdlib\Controller\Mycontroller might be a good idea.
Looking at the current "Community-Standards" having general-purpose-code under the Stdlib-Namespace is commonly accepted.
Outside of the above i don't know what to tell you, as your question is pretty vague.
I have an ASP.NET MVC app which depends on a lot of settings (name-value pairs), I am planning to store this information in a database table called SiteSettings. Is there an easy way in which I can get these settings using NHibernate. And what are the best practices when saving settings for a web application. And by settings I mean the settings which control the flow of processes in the web application and which are governed by business rules. These are not the typical connection string kind of settings. I was unable to get much information on the web on this topic. Maybe I am not searching on the right keywords, Any help will be greatly appreciated.
I can't answer in the context of nhibernate (which I'm not using) or best practices (I came up with this on my own recently). However, it works well for me, and will probably work for you.
I have a table (Biz_Config) in the database to store business preferences. (I've created a web.config section for what I call IT preferences.)
I have a class that is in charge of managing the biz preferences. The constructor grabs the entire table (one row per setting) and copies these into a dictionary, and it has methods to access (such as bizconfig.get("key")) and update this dictionary, also updating the table at the same time. It also has a few shortcut properties for specific dictionary values, especially where the value has to be cast (I have a few important numbers). It works quite well.
In order to be more efficient and not instantiate it every time I need a setting, and also to access it easily from my controllers and views, I created a static class, Globals, that is in charge of getting things out of the session or application variables. For the biz config object, it checks the application variable and, if null, creates a new one. Otherwise it just returns it. Globals is part of my helpers namespace, which is included in my web.config to be available to my views. So I can easily call:
<% Globals.Biz_Config.Get("key") %>
I hope this helps. If you'd like code, I can dig that up for you.
James
If you have a set of key/value pairs, you probably want to use a <map>. See the official NHibernate documentation or Ayende's post about 'NHibernate Mapping - <map/>'.
I have come up with a solution which is quite similar to the one suggested by James. I have an SiteSettingsService class which manages the settings for the whole site, it has a simple dependency on an interface called ISiteServiceRepository. This might not be the most elegant solution, But it is working perfectly for me. I have also configured the SiteSettingsService class as a Singleton using StructureMap. So, it saves me unnecessary instantiantion every time I need any settings.
//ISiteServiceRepository, an implementation of this uses NHibernate to do just two things
//i)Get all the settings, ii)Persist all the settings
using System.Collections.Generic;
using Cosmicvent.Mcwa.Core.Domain.Model;
namespace Cosmicvent.Mcwa.Core.Domain {
public interface ISiteServiceRepository {
IList<Setting> GetSettings();
void PersistSettings(IDictionary<string, string> settings);
}
}
//The main SiteSettingsService class depends on the ISiteServiceRepository
using System;
using System.Collections.Generic;
using Cosmicvent.Mcwa.Core.Domain;
using Cosmicvent.Mcwa.Core.Domain.Model;
namespace Cosmicvent.Mcwa.Core.Services {
public class SiteSettingsService : ISiteSettingsService {
private readonly ISiteServiceRepository _siteServiceRepository;
private IDictionary<string, string> _settings;
public SiteSettingsService(ISiteServiceRepository siteServiceRepository) {
_siteServiceRepository = siteServiceRepository;
//Fill up the settings
HydrateSettings();
}
public int ActiveDegreeId {
get {
return int.Parse(GetValue("Active_Degree_Id"));
}
}
public string SiteTitle {
get { return GetValue("Site_Title"); }
}
public decimal CounsellingFee {
get { return decimal.Parse(GetValue("Counselling_Fee")); }
}
public decimal TuitionFee {
get { return decimal.Parse(GetValue("Tuition_Fee")); }
}
public decimal RegistrationFee {
get { return decimal.Parse(GetValue("Registration_Fee")); }
}
public void UpdateSetting(string setting, string value) {
if (!string.IsNullOrEmpty(setting) && !string.IsNullOrEmpty(value)) {
SetValue(setting, value);
PersistSettings();
}
}
//Helper methods
private void HydrateSettings() {
_settings = new Dictionary<string, string>();
IList<Setting> siteRepoSettings = _siteServiceRepository.GetSettings();
if (siteRepoSettings == null) {
throw new ArgumentException("Site Settings Repository returned a null dictionary");
}
foreach (Setting setting in siteRepoSettings) {
_settings.Add(setting.Name.ToUpper(), setting.Value);
}
}
private string GetValue(string key) {
key = key.ToUpper();
if (_settings == null) {
throw new NullReferenceException("The Site Settings object is Null");
}
if (!_settings.ContainsKey(key)) {
throw new KeyNotFoundException(string.Format("The site setting {0} was not found", key));
}
return _settings[key];
}
private void SetValue(string key, string value) {
key = key.ToUpper();
if (_settings == null) {
throw new NullReferenceException("The Site Settings object is Null");
}
if (!_settings.ContainsKey(key)) {
throw new KeyNotFoundException(string.Format("The site setting {0} was not found", key));
}
_settings[key] = value;
}
private void PersistSettings() {
_siteServiceRepository.PersistSettings(_settings);
}
}
}
Hope this helps future developers facing similar problems. Any suggestions for improving this are more than welcome.