ASP.NET MVC 4 Custom Action filters with dynamic data

1.6k views Asked by At

So I am building a web application that I want to sell once Im done with it. It allows the user to enter data such as their website name, meta keywords, their contact email, phone, address etc in the admin panel. I wrote a Action Filter in order to include these values in every request that I put the filter on so I didnt have to query for them every time because these values are included in the common footer throughout the site. However, I learned that if I update the database with new or different information for these values, it does not update on the web pages which im guessing is because Action Filters are configured at application start up. In the Action Filter I am using a repository pattern to query for these values. I have included the code for the action filter below. How can I have the convenience of the Action Filter but be able to update it dynamically when the data changes in the database? Thanks!

public class ViewBagActionFilter : ActionFilterAttribute,IActionFilter
{
    Repositories.SettingsRepository _repo = new Repositories.SettingsRepository();

    void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
    }

    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
        string siteName = _repo.GetSiteName();
        string siteDesc = _repo.GetSiteDescription();
        string siteKeywords = _repo.GetSiteKeywords();
        string googleAnalytics = _repo.GetGoogleAnalytics();
        string streetAddress = _repo.GetStreetAddress();
        string zipCode = _repo.GetZipCode();
        string city = _repo.GetCity();
        string state = _repo.GetState();
        string aboutUs = _repo.GetAboutUs();
        string phone = _repo.GetPhoneNumber();
        string contactEmail = _repo.GetContactEmail();

        if (!string.IsNullOrWhiteSpace(siteName) && siteName.Length > 0)
        {
            string[] splitSiteName = new string[siteName.Length/2];
            splitSiteName = siteName.Split(' ');
            if (splitSiteName.Length > 1)
            {
                filterContext.Controller.ViewBag.SiteName1 = splitSiteName[0];
                filterContext.Controller.ViewBag.SiteName2 = splitSiteName[1];
            }
            else
            {
                filterContext.Controller.ViewBag.SiteName1 = splitSiteName[0];
                filterContext.Controller.ViewBag.SiteName2 = "";
            }
        }
        //Set default values for common viewbag items that are on every page using ternary syntax
        filterContext.Controller.ViewBag.SiteDescription = (!string.IsNullOrWhiteSpace(siteDesc) && siteDesc.Length > 0) ? siteDesc : "";
        filterContext.Controller.ViewBag.SiteKeywords = (!string.IsNullOrWhiteSpace(siteKeywords) && siteKeywords.Length > 0) ? siteKeywords : "";
        filterContext.Controller.ViewBag.GoogleAnalytics = (!string.IsNullOrWhiteSpace(googleAnalytics) && googleAnalytics.Length > 0) ? googleAnalytics : "";
        filterContext.Controller.ViewBag.StreetAddress = (!string.IsNullOrWhiteSpace(streetAddress) && streetAddress.Length > 0) ? streetAddress : "";
        filterContext.Controller.ViewBag.ZipCode = (!string.IsNullOrWhiteSpace(zipCode) && zipCode.Length > 0) ? zipCode : "";
        filterContext.Controller.ViewBag.City = (!string.IsNullOrWhiteSpace(city) && city.Length > 0) ? city : "";
        filterContext.Controller.ViewBag.State = (!string.IsNullOrWhiteSpace(state) && state.Length > 0) ? state : "";
        filterContext.Controller.ViewBag.AboutUs = (!string.IsNullOrWhiteSpace(aboutUs) && aboutUs.Length > 0) ? aboutUs : "";
        filterContext.Controller.ViewBag.PhoneNumber = (!string.IsNullOrWhiteSpace(phone) && phone.Length > 0) ? phone : "";
        filterContext.Controller.ViewBag.ContactEmail = (!string.IsNullOrWhiteSpace(contactEmail) && contactEmail.Length > 0) ? contactEmail : "";
        base.OnActionExecuting(filterContext);   
    }
}
1

There are 1 answers

0
Vova Bilyachat On BEST ANSWER

I will try to explain how action filters works.

So if you extend Action filter you can override 4 base methods :

  • OnActionExecuting – This method is called before a controller action is executed.
  • OnActionExecuted – This method is called after a controller action is executed.
  • OnResultExecuting – This method is called before a controller action result is executed.
  • OnResultExecuted – This method is called after a controller action result is executed.

So thats mean that you method will be called each time before Controller will run action.

Now about optimization. You have

string siteName = _repo.GetSiteName();
        string siteDesc = _repo.GetSiteDescription();
        string siteKeywords = _repo.GetSiteKeywords();
        string googleAnalytics = _repo.GetGoogleAnalytics();
        string streetAddress = _repo.GetStreetAddress();
        string zipCode = _repo.GetZipCode();
        string city = _repo.GetCity();
        string state = _repo.GetState();
        string aboutUs = _repo.GetAboutUs();
        string phone = _repo.GetPhoneNumber();
        string contactEmail = _repo.GetContactEmail();

I would suggest you to create one class

public class Site{
 public string SiteName{get;set;}
public string City{get;set;}
//And so on just to add all properties
}

then in repository add one more method

_repo.GetSite(); //Which will return object Site

Then

filterContext.Controller.ViewBag.CurrentSite = _repo.GetSite(); 

And now probably the most important for you. Why it doesnot work as you want and its a bit simple. Attribute class is initialized only once on Application start and after that it doesnot reloads, and your implementation is a bit strange since

 Repositories.SettingsRepository _repo = new Repositories.SettingsRepository();

I suppose here you are loading settings. So after you load you did not reload it anymore... thats mean you will get same result each time you reload page, but if you restart iis for instance you will refresh data. Possible solution

Move initialization of _repo to OnActionExecuting then it will reload data each time, or rewrite repository as i suggested and

filterContext.Controller.ViewBag.CurrentSite = _repo.GetSite(); 

Should always load new data from db.

Hope it helps :)