Where to place Entity Framework 6.0 pre-generated view - c#

I'm developing Window Forms project with Entity Framework 6.0. I apply Database-first approach and create edmx file by using Visual Studio Wizards. Like all others, I also produce pre-generated view to improve performance. I used Entity Framework Power Tools. It works and produce my_EF.views.cs file.
But my first query still take long time.
I doubt that my project file structure might be the problem. In my solution explorer, I have two projects "MyApp.GUI" (Windows Form Project) and "MyApp.DataAccess" (Class Library Project). I add reference dll of "MyApp.DataAccess" to "MyApp.GUI".
My Entity Framework edmx file is located in "MyApp.DataAccess" project. I don't know where to put my pre-generated view file whether in "MyApp.DataAccess" class library or "MyApp.GUI" windows form project. Currently the pre-generated view file is in "MyApp.DataAccess" class library.
Does my problem associated with my project file structure ? Or, may be the pre-generated view file does not work (produced by Entity Framework Power Tools) ? This is my pre-generated view file. Please suggest me possible solutions.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System.Data.Entity.Infrastructure.MappingViews;
[assembly: DbMappingViewCacheTypeAttribute(
typeof(TheWayPointOfSale.DataAccess.TheWayPOSEntities),
typeof(Edm_EntityMappingGeneratedViews.ViewsForBaseEntitySetsa6f884d523752b7a79e1bab1a97ba058ffdac6b45a04cc850e30f503a4e1fc49))]
namespace Edm_EntityMappingGeneratedViews
{
using System;
using System.CodeDom.Compiler;
using System.Data.Entity.Core.Metadata.Edm;
/// <summary>
/// Implements a mapping view cache.
/// </summary>
[GeneratedCode("Entity Framework Power Tools", "0.9.0.0")]
internal sealed class ViewsForBaseEntitySetsa6f884d523752b7a79e1bab1a97ba058ffdac6b45a04cc850e30f503a4e1fc49 : DbMappingViewCache
{
/// <summary>
/// Gets a hash value computed over the mapping closure.
/// </summary>
public override string MappingHashValue
{
get { return "a6f884d523752b7a79e1bab1a97ba058ffdac6b45a04cc850e30f503a4e1fc49"; }
}
/// <summary>
/// Gets a view corresponding to the specified extent.
/// </summary>
/// <param name="extent">The extent.</param>
/// <returns>The mapping view, or null if the extent is not associated with a mapping view.</returns>
public override DbMappingView GetView(EntitySetBase extent)
{
if (extent == null)
{
throw new ArgumentNullException("extent");
}
var extentName = extent.EntityContainer.Name + "." + extent.Name;
if (extentName == "TheWayPOSModelStoreContainer.Products")
{
return GetView0();
}
if (extentName == "TheWayPOSModelStoreContainer.Um")
{
return GetView1();
}
if (extentName == "TheWayPOSModelStoreContainer.Products_Um")
{
return GetView2();
}
if (extentName == "TheWayPOSEntities.Products")
{
return GetView3();
}
if (extentName == "TheWayPOSEntities.Ums")
{
return GetView4();
}
if (extentName == "TheWayPOSEntities.Products_Um")
{
return GetView5();
}
return null;
}
/// <summary>
/// Gets the view for TheWayPOSModelStoreContainer.Products.
/// </summary>
/// <returns>The mapping view.</returns>
private static DbMappingView GetView0()
{
return new DbMappingView(#"
SELECT VALUE -- Constructing Products
[TheWayPOSModel.Store.Products](T1.[Products.product_code], T1.[Products.product_name], T1.[Products.buying_price], T1.[Products.discount_percentage], T1.[Products.retail_price], T1.[Products.wholesale_price], T1.Products_supplier, T1.[Products.created_at], T1.[Products.updated_at])
FROM (
SELECT
T.product_code AS [Products.product_code],
T.product_name AS [Products.product_name],
T.buying_price AS [Products.buying_price],
T.discount_percentage AS [Products.discount_percentage],
T.retail_price AS [Products.retail_price],
T.wholesale_price AS [Products.wholesale_price],
T.supplier AS Products_supplier,
T.created_at AS [Products.created_at],
T.updated_at AS [Products.updated_at],
True AS _from0
FROM TheWayPOSEntities.Products AS T
) AS T1");
}
/// <summary>
/// Gets the view for TheWayPOSModelStoreContainer.Um.
/// </summary>
/// <returns>The mapping view.</returns>
private static DbMappingView GetView1()
{
return new DbMappingView(#"
SELECT VALUE -- Constructing Um
[TheWayPOSModel.Store.Um](T1.[Um.um_code], T1.[Um.um_shortname], T1.[Um.um_fullname], T1.Um_disposable, T1.[Um.disposed_um_code], T1.[Um.disposed_um_qty], T1.[Um.depend_on_product], T1.[Um.created_at], T1.[Um.updated_at])
FROM (
SELECT
T.um_code AS [Um.um_code],
T.um_shortname AS [Um.um_shortname],
T.um_fullname AS [Um.um_fullname],
T.disposable AS Um_disposable,
T.disposed_um_code AS [Um.disposed_um_code],
T.disposed_um_qty AS [Um.disposed_um_qty],
T.depend_on_product AS [Um.depend_on_product],
T.created_at AS [Um.created_at],
T.updated_at AS [Um.updated_at],
True AS _from0
FROM TheWayPOSEntities.Ums AS T
) AS T1");
}
/// <summary>
/// Gets the view for TheWayPOSModelStoreContainer.Products_Um.
/// </summary>
/// <returns>The mapping view.</returns>
private static DbMappingView GetView2()
{
return new DbMappingView(#"
SELECT VALUE -- Constructing Products_Um
[TheWayPOSModel.Store.Products_Um](T1.[Products_Um.id], T1.[Products_Um.product_code], T1.[Products_Um.um_code], T1.[Products_Um.disposed_um_code], T1.[Products_Um.disposed_um_qty])
FROM (
SELECT
T.id AS [Products_Um.id],
T.product_code AS [Products_Um.product_code],
T.um_code AS [Products_Um.um_code],
T.disposed_um_code AS [Products_Um.disposed_um_code],
T.disposed_um_qty AS [Products_Um.disposed_um_qty],
True AS _from0
FROM TheWayPOSEntities.Products_Um AS T
) AS T1");
}
/// <summary>
/// Gets the view for TheWayPOSEntities.Products.
/// </summary>
/// <returns>The mapping view.</returns>
private static DbMappingView GetView3()
{
return new DbMappingView(#"
SELECT VALUE -- Constructing Products
[TheWayPOSModel.Product](T1.[Product.product_code], T1.[Product.product_name], T1.[Product.buying_price], T1.[Product.discount_percentage], T1.[Product.retail_price], T1.[Product.wholesale_price], T1.Product_supplier, T1.[Product.created_at], T1.[Product.updated_at])
FROM (
SELECT
T.product_code AS [Product.product_code],
T.product_name AS [Product.product_name],
T.buying_price AS [Product.buying_price],
T.discount_percentage AS [Product.discount_percentage],
T.retail_price AS [Product.retail_price],
T.wholesale_price AS [Product.wholesale_price],
T.supplier AS Product_supplier,
T.created_at AS [Product.created_at],
T.updated_at AS [Product.updated_at],
True AS _from0
FROM TheWayPOSModelStoreContainer.Products AS T
) AS T1");
}
/// <summary>
/// Gets the view for TheWayPOSEntities.Ums.
/// </summary>
/// <returns>The mapping view.</returns>
private static DbMappingView GetView4()
{
return new DbMappingView(#"
SELECT VALUE -- Constructing Ums
[TheWayPOSModel.Um](T1.[Um.um_code], T1.[Um.um_shortname], T1.[Um.um_fullname], T1.Um_disposable, T1.[Um.disposed_um_code], T1.[Um.disposed_um_qty], T1.[Um.depend_on_product], T1.[Um.created_at], T1.[Um.updated_at])
FROM (
SELECT
T.um_code AS [Um.um_code],
T.um_shortname AS [Um.um_shortname],
T.um_fullname AS [Um.um_fullname],
T.disposable AS Um_disposable,
T.disposed_um_code AS [Um.disposed_um_code],
T.disposed_um_qty AS [Um.disposed_um_qty],
T.depend_on_product AS [Um.depend_on_product],
T.created_at AS [Um.created_at],
T.updated_at AS [Um.updated_at],
True AS _from0
FROM TheWayPOSModelStoreContainer.Um AS T
) AS T1");
}
/// <summary>
/// Gets the view for TheWayPOSEntities.Products_Um.
/// </summary>
/// <returns>The mapping view.</returns>
private static DbMappingView GetView5()
{
return new DbMappingView(#"
SELECT VALUE -- Constructing Products_Um
[TheWayPOSModel.Products_Um](T1.[Products_Um.id], T1.[Products_Um.product_code], T1.[Products_Um.um_code], T1.[Products_Um.disposed_um_code], T1.[Products_Um.disposed_um_qty])
FROM (
SELECT
T.id AS [Products_Um.id],
T.product_code AS [Products_Um.product_code],
T.um_code AS [Products_Um.um_code],
T.disposed_um_code AS [Products_Um.disposed_um_code],
T.disposed_um_qty AS [Products_Um.disposed_um_qty],
True AS _from0
FROM TheWayPOSModelStoreContainer.Products_Um AS T
) AS T1");
}
}
}

I know this information is not worth to be an answer. But for other newbies like me, I would like to share my experience.
According to Maarten's comment, I have put breakpoints in each of the pre-generated view files. The pre-generated view in DataAccess class library is hit by the breakpoint. So, it can be generally assume to place the pre-generated view file in DataAccess class library where edmx file is located (in my kinds of situations).

Related

Cache mechanism for .NET

***Just for learning purpose***
Recently I just knew the word cache and cache mechanism and generally understand that the cache mechanism is a good thing on system responding performance and reduce many interacting with database.
And based on the talking with someone else, they told me the general idea that we can create an independent library and cache the data retrieving from database and once we need it in our business layer, then we can retrieve it from the cache layer.
And they also shared something but not very detailed that the database can update the cache layer automatically when the data in database refreshed, like updating, adding and deleting.
So my questions comes, how does database know and update cache layer proactively and automatically? Can anybody share something with me? or are there any existing frameworks, open source solutions?
I would much appreciate for your kindly help. I'm looking forward to hearing from you my friend.
Try this third party cache: CacheCrow, it is a simple LFU based cache.
Install using powershell command in visual studio: Install-Package CacheCrow
Code Snippet:
// initialization of singleton class
ICacheCrow<string, string> cache = CacheCrow<string, string>.Initialize(1000);
// adding value to cache
cache.Add("#12","Jack");
// searching value in cache
var flag = cache.LookUp("#12");
if(flag)
{
Console.WriteLine("Found");
}
// removing value
var value = cache.Remove("#12");
For more information you can visit: https://github.com/RishabKumar/CacheCrow
Jacob,
Let me give you an example...
In the data layer when we are going to retrieve a list of objects that should be cached from the database we could to something like this.
if (!CacheHelper.Get("AllRoles", out entities))
{
var items = _context.Set<Roles>().ToList();
entities = items;
var cachableEntities = entities.ToList();
CacheHelper.Add(cachableEntities, "AllRoles");
}
return entities;
You'll notice that I have Cache helper that will search the cache for the key "AllRoles" if it finds the cache it will return the entities from the cache. If it cant find it it will get the data from the database and Create the cache with the key.
Additionally, every time we add/delete/or change an item in this table we could simple destroy this cache.
CacheHelper.Clear(CacheKey);
So answering the question, in this sample the database doesn't know when to recreate the cache, the application logic does.
Here a sample of a Cache Helpers you may use....
using System;
using System.Collections.Generic;
using System.Web;
namespace Core.Helpers
{
public static class CacheHelper
{
public static List<string> GetCacheKeys()
{
List<string> keys = new List<string>();
// retrieve application Cache enumerator
var enumerator = System.Web.HttpRuntime.Cache.GetEnumerator();
while (enumerator.MoveNext())
{
keys.Add(enumerator.Key.ToString());
}
return keys;
}
/// <summary>
/// Insert value into the cache using
/// appropriate name/value pairs
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="o">Item to be cached</param>
/// <param name="key">Name of item</param>
public static void Add<T>(T o, string key)
{
// NOTE: Apply expiration parameters as you see fit.
// I typically pull from configuration file.
// In this example, I want an absolute
// timeout so changes will always be reflected
// at that time. Hence, the NoSlidingExpiration.
if (HttpContext.Current != null)
HttpContext.Current.Cache.Insert(
key,
o,
null,
DateTime.Now.AddMinutes(1440),
System.Web.Caching.Cache.NoSlidingExpiration);
}
/// <summary>
/// Remove item from cache
/// </summary>
/// <param name="key">Name of cached item</param>
public static void Clear(string key)
{
if (HttpContext.Current != null)
HttpContext.Current.Cache.Remove(key);
}
/// <summary>
/// Check for item in cache
/// </summary>
/// <param name="key">Name of cached item</param>
/// <returns></returns>
public static bool Exists(string key)
{
var exists= HttpContext.Current != null && HttpContext.Current.Cache[key] != null;
return exists;
}
/// <summary>
/// Retrieve cached item
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Name of cached item</param>
/// <param name="value">Cached value. Default(T) if
/// item doesn't exist.</param>
/// <returns>Cached item as type</returns>
public static bool Get<T>(string key, out T value)
{
try
{
if (!Exists(key))
{
value = default(T);
return false;
}
value = (T)HttpContext.Current.Cache[key];
}
catch
{
value = default(T);
return false;
}
return true;
}
}
}

Unable to cast object of type Page to type 'Windows.UI.Xaml.Controls.Frame' when using mvvm-light navigation service in a win 10 universal app

I m hitting the following error on my new windows 10 universal app C#/XAML:
An exception of type 'System.InvalidCastException' occurred in GalaSoft.MvvmLight.Platform.dll but was not handled in user code
Additional information: Unable to cast object of type '' to type 'Windows.UI.Xaml.Controls.Frame'.
on the following navigating command in one of my page's view model:
_navigationService.NavigateTo(ViewModelLocator.MedicineBoxPageKey);
I am trying to have a hamburger menu style navigation (see this sample). app by Microsoft on an example of how to do this) to:
1- have a convenient solution shared across all my pages. The sample mentioned above uses an AppShell Page as the root of the app instead of a Frame, that encapsulates the navigation menu and some behavior of the back button. That would be ideal.
2- Use the MVVM-Light navigation service to handle all the navigation from my view model conveniently.
Here is how the App.xml.Cs initializes the shell page onLaunched:
AppShell shell = Window.Current.Content as AppShell;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (shell == null)
{
// Create a a AppShell to act as the navigation context and navigate to the first page
shell = new AppShell();
// Set the default language
shell.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
shell.AppFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
}
// Place our app shell in the current Window
Window.Current.Content = shell;
if (shell.AppFrame.Content == null)
{
// When the navigation stack isn't restored, navigate to the first page
// suppressing the initial entrance animation.
shell.AppFrame.Navigate(typeof(MedicinesStorePage), e.Arguments, new Windows.UI.Xaml.Media.Animation.SuppressNavigationTransitionInfo());
}
// Ensure the current window is active
Window.Current.Activate();
And here is the AppShell class definition:
public sealed partial class AppShell : Page
{
public static AppShell Current = null;
public AppShell()
{
this.InitializeComponent();
}
}
From what I have tried so far, the mvvm-light navigation service only works when a Frame is used a root of the app and note a Page (otherwise we get this casting bug).
However using a Frame does not seem to be a option either since as the sample app puts it:
Using a Page as the root for the app provides a design time experience as well as ensures that
when it runs on Mobile the app content won't appear under the system's StatusBar which is visible
by default with a transparent background. It will also take into account the presence of software
navigation buttons if they appear on a device. An app can opt-out by switching to UseCoreWindow.
I also tried to overide the navigationTo method from the mvvm-light navigation service but the bug seems to occur before I could catch it.
Does anyone has a solution to use the mvvm-light navigation service and a shell page as the app root (that manages the hamburger menu, etc.)?
Thanks a lot!
I talked to Laurent Bugnion and he recommended me to implemented my own navigation service who handles the navigation. For this I made a PageNavigationService who implements the INavigationService Interface of MVVM Light.
public class PageNavigationService : INavigationService
{
/// <summary>
/// The key that is returned by the <see cref="CurrentPageKey" /> property
/// when the current Page is the root page.
/// </summary>
public const string RootPageKey = "-- ROOT --";
/// <summary>
/// The key that is returned by the <see cref="CurrentPageKey" /> property
/// when the current Page is not found.
/// This can be the case when the navigation wasn't managed by this NavigationService,
/// for example when it is directly triggered in the code behind, and the
/// NavigationService was not configured for this page type.
/// </summary>
public const string UnknownPageKey = "-- UNKNOWN --";
private readonly Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
/// <summary>
/// The key corresponding to the currently displayed page.
/// </summary>
public string CurrentPageKey
{
get
{
lock (_pagesByKey)
{
var frame = ((AppShell) Window.Current.Content).AppFrame;
if (frame.BackStackDepth == 0)
{
return RootPageKey;
}
if (frame.Content == null)
{
return UnknownPageKey;
}
var currentType = frame.Content.GetType();
if (_pagesByKey.All(p => p.Value != currentType))
{
return UnknownPageKey;
}
var item = _pagesByKey.FirstOrDefault(
i => i.Value == currentType);
return item.Key;
}
}
}
/// <summary>
/// If possible, discards the current page and displays the previous page
/// on the navigation stack.
/// </summary>
public void GoBack()
{
var frame = ((Frame) Window.Current.Content);
if (frame.CanGoBack)
{
frame.GoBack();
}
}
/// <summary>
/// Displays a new page corresponding to the given key.
/// Make sure to call the <see cref="Configure" />
/// method first.
/// </summary>
/// <param name="pageKey">
/// The key corresponding to the page
/// that should be displayed.
/// </param>
/// <exception cref="ArgumentException">
/// When this method is called for
/// a key that has not been configured earlier.
/// </exception>
public void NavigateTo(string pageKey)
{
NavigateTo(pageKey, null);
}
/// <summary>
/// Displays a new page corresponding to the given key,
/// and passes a parameter to the new page.
/// Make sure to call the <see cref="Configure" />
/// method first.
/// </summary>
/// <param name="pageKey">
/// The key corresponding to the page
/// that should be displayed.
/// </param>
/// <param name="parameter">
/// The parameter that should be passed
/// to the new page.
/// </param>
/// <exception cref="ArgumentException">
/// When this method is called for
/// a key that has not been configured earlier.
/// </exception>
public void NavigateTo(string pageKey, object parameter)
{
lock (_pagesByKey)
{
if (!_pagesByKey.ContainsKey(pageKey))
{
throw new ArgumentException(
string.Format(
"No such page: {0}. Did you forget to call NavigationService.Configure?",
pageKey),
"pageKey");
}
var shell = ((AppShell) Window.Current.Content);
shell.AppFrame.Navigate(_pagesByKey[pageKey], parameter);
}
}
/// <summary>
/// Adds a key/page pair to the navigation service.
/// </summary>
/// <param name="key">
/// The key that will be used later
/// in the <see cref="NavigateTo(string)" /> or <see cref="NavigateTo(string, object)" /> methods.
/// </param>
/// <param name="pageType">The type of the page corresponding to the key.</param>
public void Configure(string key, Type pageType)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(key))
{
throw new ArgumentException("This key is already used: " + key);
}
if (_pagesByKey.Any(p => p.Value == pageType))
{
throw new ArgumentException(
"This type is already configured with key " + _pagesByKey.First(p => p.Value == pageType).Key);
}
_pagesByKey.Add(
key,
pageType);
}
}
}
Basicly it's a copy of his implementation. But instead of parsing to a Frame I parse to an AppShell and use the AppFrame Property to navigate.
I put this to my ViewModelLocator. Instead of:
var navigationService = new NavigationService();
I will just use:
var navigationService = new PageNavigationService();
EDIT: I Noticed that there is an excpetion in the NavMenuListView when you use the backkey after you navigated with the new navigationservice since the selected item is null. I fixed it with adjusting the SetSelectedItem Method and adding a nullcheck in the for loop after the cast:
public void SetSelectedItem(ListViewItem item)
{
var index = -1;
if (item != null)
{
index = IndexFromContainer(item);
}
for (var i = 0; i < Items.Count; i++)
{
var lvi = (ListViewItem) ContainerFromIndex(i);
if(lvi == null) continue;
if (i != index)
{
lvi.IsSelected = false;
}
else if (i == index)
{
lvi.IsSelected = true;
}
}
}
But there might be a more elegant solution than this.

WFFM - Sitecore : linking dropdown to user profile

I'm using Sitecore 8 Update 2 and the WFFM module.
I created a register page using WFFM and everything works fine except for the values in the dropdown lists ( zipcode, city, gender, ... )
I linked all the form fields to the profile fields but these values never get filled in. I tried linking the form dropdown to a dropdown field on the profile, to a simple text field on the profile, but it never fills in any value.
Does anyone know why this is and what i can do to link these fields ?
This is a bug in WFFM. To fix it, add the code below to your solution then go to the item /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/List Types/Drop List and set the field MVC Type to {your namespace}.DropListField,[your dll name}
namespace {your namespace}
{
using System.Collections.Generic;
using System.Linq;
using Sitecore.Data.Items;
using Sitecore.Form.Core.Controls.Data;
/// <summary>
/// The drop list field.
/// </summary>
public class DropListField : Sitecore.Forms.Mvc.Models.Fields.DropListField
{
/// <summary>
/// Initialises a new instance of the <see cref="DropListField"/> class.
/// </summary>
/// <param name="item">
/// The item.
/// </param>
public DropListField(Item item)
: base(item)
{
}
/// <summary>
/// The get result.
/// </summary>
/// <returns>
/// The <see cref="ControlResult"/>.
/// </returns>
public override ControlResult GetResult()
{
var value = this.Value as List<string>;
var selectListItem = this.Items.SingleOrDefault(x => x.Value == value.First());
var str = selectListItem != null ? selectListItem.Text : string.Empty;
return new ControlResult(this.ID.ToString(), this.Title, selectListItem != null ? selectListItem.Value : string.Empty, str);
}
}
}
Sounds like it could be this bug:
http://www.cmsbestpractices.com/bug-sitecore-8-with-web-forms-for-marketers-drop-list-entries-not-being-properly-recorded-in-xdb/
Use Robomongo to check if the values are being stored properly in MongoDB.

Should Controllers read custom app settings from web.config?

In my mvc application during certain times of the year we want to show one of two links. Basically I have to switch the link when I get a call from management. So, I thought instead of having to recompile the app I would add a custom app setting to the web.config file. Then I created a wrapper so that it is strongly typed. Now, my problem is I don't know where to execute the logic. Should add a property to my view model and set it in the controller based on the configuration setting value? Or should I read it directly in my View and toggle between the two links? I'm pretty sure this only belongs in the view or the controller, and not the service layer, since it is used specifically for UI stuff.
Details.cshtml //current code
#if(Search.App.ParcelDetailDisplayMode == Search.App.DisplayMode.Tax ){
<a id="tax-link" href="#taxlink" title="View Tax Bill on Tax Collectors Website">Tax Bill</a>
}
else if(Search.App.ParcelDetailDisplayMode == Search.App.DisplayMode.Trim ){
<a id="trim-link" href="#trimlink" title="View your TRIM notice online">Trim Notice</a>
}
web.config
<add key="ParcelDetailDisplayMode" value="Tax"/>
config wrapper
namespace Search
{
/// <summary>
/// The app.
/// </summary>
public static class App
{
/// <summary>
/// Gets the tax bill link.
/// </summary>
public static string TaxBillLink
{
get
{
return ConfigurationManager.AppSettings["TaxBillLink"];
}
}
/// <summary>
/// Gets the trim notice link.
/// </summary>
public static string TrimNoticeLink
{
get
{
return ConfigurationManager.AppSettings["TrimLink"];
}
}
/// <summary>
/// Gets the map link.
/// </summary>
public static string MapLink
{
get
{
return ConfigurationManager.AppSettings["MapLink"];
}
}
/// <summary>
/// Gets the update address link.
/// </summary>
public static string UpdateAddressLink
{
get
{
return ConfigurationManager.AppSettings["UpdateAddressLink"];
}
}
/// <summary>
/// Gets the release name.
/// </summary>
public static string ReleaseName
{
get
{
return ConfigurationManager.AppSettings["ReleaseName"];
}
}
/// <summary>
/// Gets the parcel detail display mode.
/// </summary>
public static DisplayMode ParcelDetailDisplayMode
{
get
{
var r = DisplayMode.Tax;
DisplayMode.TryParse(ConfigurationManager.AppSettings["ParcelDetailDisplayMode"], out r);
return r;
}
}
/// <summary>
/// The display mode.
/// </summary>
public enum DisplayMode
{
/// <summary>
/// The trim.
/// </summary>
Trim,
/// <summary>
/// The tax.
/// </summary>
Tax
}
}
}
I would say it does not really matter. Adding it as a property of your model feels to give a little bit more separation.
What does matter though is that your wrapper is static. This will make it really difficult to mock it for the purpose of unit testing (or any other purpose)
There should be no logic in the controller.
Read this for example: Where should I put my controller business logic in MVC3
or this one: https://softwareengineering.stackexchange.com/questions/165444/where-to-put-business-logic-in-mvc-design
I know it's tempting but the less logic you put there the best you will find yourself in the future.
the answer in my opinion is:
You should read your property in a business layer benhead the controller and pass it all the way up to the view in a model object.
I agree with Maurizio in general that all business logic should be in some service/business logic layer. However in this case since you're only fetching a value from web.config whether, in your controller action, you do:
var someValue = App.TaxBillLink;
or you do:
var someValue = _linkService.GetTodaysLink();
really doesn't matter much unless there is some sort of logic there that needs to be unit tested.

ASP.net "BasePage" class ideas

What cool functionality and methods do you add to your ASP.net BasePage : System.Web.UI.Page classes?
Examples
Here's something I use for authentication, and I'd like to hear your opinions on this:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
// Authentication code omitted... Essentially same as below.
if (_RequiresAuthentication && !(IsAuthorized))
{
RespondForbidden("You do not have permissions to view this page.", UnauthorizedRedirect);
return;
}
}
// This function is overridden in each page subclass and fitted to each page's
// own authorization requirements.
// This also allows cascading authorization checks,
// e.g: User has permission to view page? No - base.IsAuthorized - Is user an admin?
protected virtual bool IsAuthorized
{
get { return true; }
}
My BasePage class contains an instance of this class:
public class StatusCodeResponse {
public StatusCodeResponse(HttpContext context) {
this._context = context;
}
/// <summary>
/// Responds with a specified status code, and if specified - transfers to a page.
/// </summary>
private void RespondStatusCode(HttpContext context, System.Net.HttpStatusCode status, string message, string transfer)
{
if (string.IsNullOrEmpty(transfer))
{
throw new HttpException((int)status, message);
}
context.Response.StatusCode = (int)status;
context.Response.StatusDescription = message;
context.Server.Transfer(transfer);
}
public void RespondForbidden(string message, string transfer)
{
RespondStatusCode(this._context, System.Net.HttpStatusCode.Forbidden, message, transfer);
}
// And a few more like these...
}
As a side note, this could be accomplished using extension methods for the HttpResponse object.
And another method I find quite handy for parsing querystring int arguments:
public bool ParseId(string field, out int result)
{
return (int.TryParse(Request.QueryString[field], out result) && result > 0);
}
Session related stuff, some complex object in the BasePage that maps to a session, and expose it as a property.
Doing stuff like filling a crumble pad object.
But most important: do not make your basepage into some helper class. Don't add stuff like ParseId(), that's just ridiculous.
Also, based on the first post: make stuff like IsAuthorized abstract. This way you don't create giant security holes if someone forgets that there is some virtual method.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace MySite
{
/// <summary>
/// Base class with properties for meta tags for content pages
/// http://www.codeproject.com/KB/aspnet/PageTags.aspx
/// http://weblogs.asp.net/scottgu/archive/2005/08/02/421405.aspx
/// </summary>
public partial class BasePage : System.Web.UI.Page
{
private string keywords;
private string description;
/// <SUMMARY>
/// Gets or sets the Meta Keywords tag for the page
/// </SUMMARY>
public string Meta_Keywords
{
get
{
return keywords;
}
set
{
// Strip out any excessive white-space, newlines and linefeeds
keywords = Regex.Replace(value, "\\s+", " ");
}
}
/// <SUMMARY>
/// Gets or sets the Meta Description tag for the page
/// </SUMMARY>
public string Meta_Description
{
get
{
return description;
}
set
{
// Strip out any excessive white-space, newlines and linefeeds
description = Regex.Replace(value, "\\s+", " ");
}
}
// Constructor
// Add an event handler to Init event for the control
// so we can execute code when a server control (page)
// that inherits from this base class is initialized.
public BasePage()
{
Init += new EventHandler(BasePage_Init);
}
// Whenever a page that uses this base class is initialized,
// add meta keywords and descriptions if available
void BasePage_Init(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Meta_Keywords))
{
HtmlMeta tag = new HtmlMeta();
tag.Name = "keywords";
tag.Content = Meta_Keywords;
Header.Controls.Add(tag);
}
if (!String.IsNullOrEmpty(Meta_Description))
{
HtmlMeta tag = new HtmlMeta();
tag.Name = "description";
tag.Content = Meta_Description;
Header.Controls.Add(tag);
}
}
}
}
Along with the metadata already mentioned (mostly obsolete in ASP.NET 4.0 with the new Page.MetaDescription and Page.MetaKeywords properties), I've also had methods to add other header links to my page such as specific ones for adding page specific CSS, or things like cannonical links, RSS links, etc:
/// <overloads>
/// Adds a CSS link to the page. Useful when you don't have access to the
/// HeadContent ContentPlaceHolder. This method has 4 overloads.
/// </overloads>
/// <summary>
/// Adds a CSS link.
/// </summary>
/// <param name="pathToCss">The path to CSS file.</param>
public void AddCss(string pathToCss) {
AddCss(pathToCss, string.Empty);
}
/// <summary>
/// Adds a CSS link in a specific position.
/// </summary>
/// <param name="pathToCss">The path to CSS.</param>
/// <param name="position">The postion.</param>
public void AddCss(string pathToCss, int? position) {
AddCss(pathToCss, string.Empty, position);
}
/// <summary>
/// Adds a CSS link to the page with a specific media type.
/// </summary>
/// <param name="pathToCss">The path to CSS file.</param>
/// <param name="media">The media type this stylesheet relates to.</param>
public void AddCss(string pathToCss, string media) {
AddHeaderLink(pathToCss, "text/css", "Stylesheet", media, null);
}
/// <summary>
/// Adds a CSS link to the page with a specific media type in a specific
/// position.
/// </summary>
/// <param name="pathToCss">The path to CSS.</param>
/// <param name="media">The media.</param>
/// <param name="position">The postion.</param>
public void AddCss(string pathToCss, string media, int? position) {
AddHeaderLink(pathToCss, "text/css", "Stylesheet", media, position);
}
/// <overloads>
/// Adds a general header link. Useful when you don't have access to the
/// HeadContent ContentPlaceHolder. This method has 3 overloads.
/// </overloads>
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
public void AddHeaderLink(string href, string type) {
AddHeaderLink(href, type, string.Empty, string.Empty, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
public void AddHeaderLink(string href, string type, string rel) {
AddHeaderLink(href, type, rel, string.Empty, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
/// <param name="media">The media target of the link.</param>
public void AddHeaderLink(string href, string type, string rel, string media)
{
AddHeaderLink(href, type, rel, media, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
/// <param name="media">The media target of the link.</param>
/// <param name="position">The postion in the control order - leave as null
/// to append to the end.</param>
public void AddHeaderLink(string href, string type, string rel, string media,
int? position) {
var link = new HtmlLink { Href = href };
if (0 != type.Length) {
link.Attributes.Add(HtmlTextWriterAttribute.Type.ToString().ToLower(),
type);
}
if (0 != rel.Length) {
link.Attributes.Add(HtmlTextWriterAttribute.Rel.ToString().ToLower(),
rel);
}
if (0 != media.Length) {
link.Attributes.Add("media", media);
}
if (null == position || -1 == position) {
Page.Header.Controls.Add(link);
}
else
{
Page.Header.Controls.AddAt((int)position, link);
}
}
Culture initialization by overriding InitializeCulture() method (set culture and ui culture from cookie or DB).
Some of my applications are brandable, then here I do some "branding" stuff too.
I use this methot and thanks for yours,
/// <summary>
/// Displays the alert.
/// </summary>
/// <param name="message">The message to display.</param>
protected virtual void DisplayAlert(string message)
{
ClientScript.RegisterStartupScript(
GetType(),
Guid.NewGuid().ToString(),
string.Format("alert('{0}');", message.Replace("'", #"\'")),
true
);
}
/// <summary>
/// Finds the control recursive.
/// </summary>
/// <param name="id">The id.</param>
/// <returns>control</returns>
protected virtual Control FindControlRecursive(string id)
{
return FindControlRecursive(id, this);
}
/// <summary>
/// Finds the control recursive.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="parent">The parent.</param>
/// <returns>control</returns>
protected virtual Control FindControlRecursive(string id, Control parent)
{
if (string.Compare(parent.ID, id, true) == 0)
return parent;
foreach (Control child in parent.Controls)
{
Control match = FindControlRecursive(id, child);
if (match != null)
return match;
}
return null;
}
Putting authorization code in a base page is generally not a good idea. The problem is, what happens if you forget to derive a page that needs authorization from the base page? You will have a security hole.
It's much better to use an HttpModule, so that you can intercept requests for all pages, and make sure users are authorized even before the HttpHandler has a chance to run.
Also, as others have said, and in keeping with OO principles, it's better to only have methods in your base page that actually relate to the Page itself. If they don't reference "this," they should probably be in a helper class -- or perhaps be extension methods.
I inherit from System.Web.UI.Page when I need certain properties and every page. This is good for aweb application that implements a login. In the membership pages I use my own base class to get access to Properties like UserID, UserName etc. These properties wrap Session Variables
Here are some examples (sans code) that I use a custom base class for:
Adding a page filter (e.g. replace "{theme}" with "~/App_Theme/[currentTheme]"),
Adding a Property and handling for Auto Titling pages based upon Site Map,
Registering specialized logging (could probably be redone via different means),
Adding methods for generalized input(Form/Querystring) validation, with blanket redirector: AddRequiredInput("WidgetID", PageInputType.QueryString, typeof(string)),
Site Map Helpers, allowing for things like changing a static "Edit Class" into something context related like "Edit Fall '10 Science 101"
ViewState Helpers, allowing me to register variable on the page to a name and have it automatically populate that variable from the viewstate or a default, and save the value back out to the viewstate at the end of the request.
Custom 404 Redirector, where I can pass an exception or message (or both) and it will go to a page I have predefined to nicely display and log it.
I personally like #5 the most because a) updating the SiteMap is ugly and I prefer not to have clutter the page, making it more readable, b) It makes the SiteMap much more user friendly.
,
Please refer Getting page specific info in ASP.Net Base Page
public abstract string AppSettingsRolesName { get; }
List<string> authorizedRoles = new List<string>((ConfigurationManager.AppSettings[AppSettingsRolesName]).Split(','))
if (!authorizedRoles.Contains(userRole))
{
Response.Redirect("UnauthorizedPage.aspx");
}
In derived Page
public override string AppSettingsRolesName
{
get { return "LogsScreenRoles"; }
}

Categories

Resources