Cache mechanism for .NET - c#

***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;
}
}
}

Related

WPF MVVM Communication with Messenger (post-message load of VM)

Background
I am writing a WPF application using the MVVM pattern. I am using a Messenger to communicate between ViewModels as I learned in various tutorials. I am using the implementation of a Messenger class found in the Code section of this post (thanks to #Dalstroem WPF MVVM communication between View Model and Gill Cleeren at Pluralsight).
Due to the large number of Views/VMs needed by my app, each ViewModel is instantiated at the time a View is required and disposed subsequently (view-first, VM specified as DataContext of View).
Issue
The constructor of each ViewModel loads resources (Commands, Services, etc.) as necessary, and registers for messages of interest. Messages that were sent from a previously existing ViewModels are not picked up by new ViewModels.
Thus, I cannot communicate between ViewModels using my Messenger class.
Thoughts
Some examples I've seen use a ViewModelLocator that instantiates all ViewModels upfront. The Views, when created, simply pull the existing ViewModel from the VML. This approach means that Messages will always be received and available in every ViewModel. My concern is that with 30+ ViewModels that all load a substantial amount of data with use, my app will become slow with extended use as each View is used (no resources ever disposed).
I've considered finding a way to store Messages and subsequently resend all messages to any registered recipients. If implemented, this would allow me to call a Resend method of sorts after registering for messages in each ViewModel. I have a few concerns with this approach, including the accumulation of messages over time.
I'm not sure what I'm doing wrong or if there are approachs I just don't know about.
Code
public class Messenger
{
private static readonly object CreationLock = new object();
private static readonly ConcurrentDictionary<MessengerKey, object> Dictionary = new ConcurrentDictionary<MessengerKey, object>();
#region Default property
private static Messenger _instance;
/// <summary>
/// Gets the single instance of the Messenger.
/// </summary>
public static Messenger Default
{
get
{
if (_instance == null)
{
lock (CreationLock)
{
if (_instance == null)
{
_instance = new Messenger();
}
}
}
return _instance;
}
}
#endregion
/// <summary>
/// Initializes a new instance of the Messenger class.
/// </summary>
private Messenger()
{
}
/// <summary>
/// Registers a recipient for a type of message T. The action parameter will be executed
/// when a corresponding message is sent.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="recipient"></param>
/// <param name="action"></param>
public void Register<T>(object recipient, Action<T> action)
{
Register(recipient, action, null);
}
/// <summary>
/// Registers a recipient for a type of message T and a matching context. The action parameter will be executed
/// when a corresponding message is sent.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="recipient"></param>
/// <param name="action"></param>
/// <param name="context"></param>
public void Register<T>(object recipient, Action<T> action, object context)
{
var key = new MessengerKey(recipient, context);
Dictionary.TryAdd(key, action);
}
/// <summary>
/// Unregisters a messenger recipient completely. After this method is executed, the recipient will
/// no longer receive any messages.
/// </summary>
/// <param name="recipient"></param>
public void Unregister(object recipient)
{
Unregister(recipient, null);
}
/// <summary>
/// Unregisters a messenger recipient with a matching context completely. After this method is executed, the recipient will
/// no longer receive any messages.
/// </summary>
/// <param name="recipient"></param>
/// <param name="context"></param>
public void Unregister(object recipient, object context)
{
object action;
var key = new MessengerKey(recipient, context);
Dictionary.TryRemove(key, out action);
}
/// <summary>
/// Sends a message to registered recipients. The message will reach all recipients that are
/// registered for this message type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
public void Send<T>(T message)
{
Send(message, null);
}
/// <summary>
/// Sends a message to registered recipients. The message will reach all recipients that are
/// registered for this message type and matching context.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
/// <param name="context"></param>
public void Send<T>(T message, object context)
{
IEnumerable<KeyValuePair<MessengerKey, object>> result;
if (context == null)
{
// Get all recipients where the context is null.
result = from r in Dictionary where r.Key.Context == null select r;
}
else
{
// Get all recipients where the context is matching.
result = from r in Dictionary where r.Key.Context != null && r.Key.Context.Equals(context) select r;
}
foreach (var action in result.Select(x => x.Value).OfType<Action<T>>())
{
// Send the message to all recipients.
action(message);
}
}
protected class MessengerKey
{
public object Recipient { get; private set; }
public object Context { get; private set; }
/// <summary>
/// Initializes a new instance of the MessengerKey class.
/// </summary>
/// <param name="recipient"></param>
/// <param name="context"></param>
public MessengerKey(object recipient, object context)
{
Recipient = recipient;
Context = context;
}
/// <summary>
/// Determines whether the specified MessengerKey is equal to the current MessengerKey.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
protected bool Equals(MessengerKey other)
{
return Equals(Recipient, other.Recipient) && Equals(Context, other.Context);
}
/// <summary>
/// Determines whether the specified MessengerKey is equal to the current MessengerKey.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((MessengerKey)obj);
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
unchecked
{
return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397) ^ (Context != null ? Context.GetHashCode() : 0);
}
}
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Update
The way my application is architectured, there is a ViewModel used with my MainWindow, which serves as a sort of basic shell. It provides a primary layout with a few controls for navigation and login/logout, etc.
All subsequent Views are displayed inside a ContentControl inside the MainWindow (taking up most of the window real estate). The ContentControl is bound to a "CurrentView" property of my "MainWindowViewModel." The MainWindowViewModel instantiates a custom Navigation service I created for the purpose of selecting and returning the appropriate View to update my "CurrentView" property.
This architecture may be unorthodox, but I wasn't sure how navigation is typically accompished without using out-the-box things like TabControl.
Idea
Building on ideas from #axlj, I could keep an ApplicationState object as a property of my "MainWindowViewModel." Using my Messenger class, I could pub an ApplicationState message whenever injecting a new View in my MainWindow. The ViewModels for each View would, of course, sub this message and gain state immediately upon creation. If any ViewModels make changes to their copy of ApplicationState, they would pub a message. The MainWindowViewModel would then be updated via its subscription.
I would recommend against "storing messages" -- even if you work out a good pattern for recovering messages, you'll still end up with logic that is difficult to test. This is really a sign that your view models need to know too much about the application state.
In the case of view model locator -- a well designed view model locator will likely lazy-load the view models, which would leave you in the same place you are right now.
Option 1
Instead, consider using UserControls and DependencyProperties where possible.
Option 2
If your views are in fact really views, then consider a singleton context class that maintains the necessary state and inject that into your view models. The benefit of this method is that your context class can implement INotifyPropertyChanged and any changes will automatically be propagated to your consuming views.
Option 3
If you're navigating between views, you may want to implement a Navigation service similar to something described here.
interface INavigationService(string location, object parameter) {}
In this case, your parameter is considered your state object. The new view model receives the model data from the view you're navigating away from.
This blog post is helpful in explaining best practices around when to use view models and user controls.
...and registers for messages of interest. Messages that were sent from a previously existing ViewModels are not picked up by new ViewModels. Thus, I cannot communicate between ViewModels using my Messenger class.
Why exactly do your VMs need to be aware of historical messages?
Generally messaging should be pub/sub; messages are published ("pub") and anyone who might be interested in specific messages subscribes ("sub") to receive those. The publisher shouldn't care what is done with the message - that is up to the subscriber.
If you have some obscure business case that requires knowledge of previous messages then you should create your own message queue mechanism (i.e. store them in a database and retrieve them based on datetime).

C# OData set default properties returned by $select

I'm doing a custom EnableQueryAttribute to block some properties from being queryable:
[EnableSpecificQueryable(AllowedSelectProperties = "Id, FirstName, LastName")]
It's working, but if no query is sent (only something like http://foo.bar/api/foo), ValidateQuery and ApplyQuery (see EnableQueryAttribute) are never called and the default behavior shows all Properties, what I don't want. How to manage this problem ? Where do I have to write the code for this situation ?
After this, I have some questions about general design. IMO, View Model are really bad when it comes to maintain it. It has a lot of duplicate code and a lot of file for not that much.
1. What is the best way to limit what properties can be returned by an Action ?
I really love the idea to simply give a list of property name on each Action than using hundred of view models. Sadly this only apply to GET request and I would like to do the same for post and patch.
2. How can I apply the same design for POST/PUT/PATCH without using redundant code like View Model ?
The answer to this question needs to take into account specialized Data annotation for each Action (being able to override Model's data annotation and adding new validations).
I'm working with OData in a Web APi project using Entity Framework Code First.
Thank you!
There are two parts to this solution, GET/read operations and write operations. Lets focus on read operations first.
Inside the custom EnableQueryAttribute there are two methods that you can override that might help in this scenario:
OnActionExecuting
Here you can manipulate the url before the WebAPI request is processed.
you can easily re-write the url without having to worry about recreating the whole OData context, but... you don't have any context information about the controller other than what you have passed in through the attribuite
/// <summary>
/// Manipulate the URL before the WebAPI request has been processed.
/// </summary>
/// <remarks>Simplifies logic and post-processing operations</remarks>
/// <param name="actionContext"></param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Perform operations that require modification of the Url in OnActionExecuting instead of ApplyQuery.
// Apply Query should not modify the original Url if you can help it because there can be other validator
// processes that already have expectations on the output matching the original input request.
// This goes for injecting or mofying $select, $expand or $count parameters
// Modify the actionContext request directly before returning the base operation
// actionContext.Request.RequestUri = new Uri(modifiedUrl);
base.OnActionExecuting(actionContext);
}
My original answer was based on ODataLib v5, I was a little bit naïve at the time and we were allowed to do things differently back then, so I had suggested this override
ApplyQuery This method operates almost at the end of the request, you are given the IQueryable after your controller logic has modified/created the query (which is another valid place in the pipeline to do these types of manipulations)
Unfortunately, making changes to the query at this stage can break the default OData Serialization if you change the structure of the result. There are ways around it, but you have to manipulate the ODataQuerySettings as well as the query AND you have to modify the original URL. So Apply Query is now better reserved for passive logical operations that do not need to modify the query, but rather operate on the query, perhaps for logging or some security operations
/// <summary>
/// Applies the query to the given IQueryable based on incoming query from uri and
/// query settings.
/// </summary>
/// <param name="queryable">The original queryable instance from the response message.</param>
/// <param name="queryOptions">The System.Web.OData.Query.ODataQueryOptions instance constructed based on the incomming request</param>
public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
{
// TODO: add your custom logic here
return base.ApplyQuery(entity, options);
}
TL;DR - A Solution for GET Requests!
We want to provide a default $select when none is provided
We want to restrict any values for $select to only our specified fields
For this example we will put our logic in OnActionExecuting override, because it will be very simple, we will not need to worry about this logic inside our controller logic, we wont have to manipulate any IQueryable expressions and finally the important one:
The ODataQueryOptions that are generated by the request URI are used to constrain the response payload during Serialization, so even if we select or include additional fields or navigation properties in our controller logic, the serialiser will constrain the response to only include the fields specified in $select and $expand
And that is what we want to do here, constrain all outputs from our controller so that only a subset of fields are available.
/// <summary>
/// Manipulate the URL before the WebAPI request has been processed.
/// AllowedSelectProperties may contain a CSV list of allowed field names to $select
/// </summary>
/// <remarks>If AllowedSelectProperties does not have a value, do not modify the request</remarks>
/// <param name="actionContext">Current Action context, access the Route defined parameters and the raw http request</param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Only modify the request if AllowedSelectProperties has been specified
if (!String.IsNullOrWhiteSpace(this.AllowedSelectProperties))
{
// parse the url parameters so we can process them
var tokens = actionContext.Request.RequestUri.ParseQueryString();
// CS: Special Case - if $apply is requested, DO NOT process defaults, $apply must be fully declared in terms of outputs and filters by the caller
// $apply is outside of the scope of this question :) so if it exists, skip this logic.
if (String.IsNullOrEmpty(tokens["$apply"]))
{
// check the keys, do not evaluate if the value is empty, empty is allowed
// if $expand is specified, and by convention and should not return any fields from the root element
if (!tokens.AllKeys.Contains("$select"))
tokens["$select"] = this.AllowedSelectProperties;
else
{
// We need to parse and modify the $select token
var select = tokens["$select"];
IEnumerable<string> selectFields = select.Split(',').Select(x => x.Trim());
IEnumerable<string> allowedFields = this.AllowedSelectProperties.Split(',').Select(x => x.Trim());
// Intersect allows us to ujse our allowedFields as a MASK against the requested fields
// NOTE: THIS IS PASSIVE, you could throw an exception if you want to prevent execution when an invalid field is requested.
selectFields = selectFields.Intersect(allowedFields, StringComparer.OrdinalIgnoreCase);
tokens["$select"] = string.Join(",", selectFields);
}
// Rebuild our modified URI
System.Text.StringBuilder result = new System.Text.StringBuilder();
result.Append(actionContext.Request.RequestUri.AbsoluteUri.Split('?').First());
if (tokens.Count > 0)
{
result.Append("?");
result.Append(String.Join("&",
tokens.AllKeys.Select(key =>
String.Format("{0}={1}", key, Uri.EscapeDataString(tokens[key]))
)
)
);
}
// Apply the modified Uri to the action context
actionContext.Request.RequestUri = new Uri(result.ToString());
}
}
// Allow the base logic to complete
base.OnActionExecuting(actionContext);
}
TL;DR - Regarding Write operations
How can I apply the same design for POST/PUT/PATCH without using redundant code like View Model ?
We can't really affect write operations as easily in the EnableQueryAttribute, we can't use ApplyQuery override, because this executes after the action
(yes you can still return a query from a POST/PUT/PATCH if your controller chooses to do so - lets argue about that later)
But we also cannot modify the POST/PUT in the OnActionExecuting before the request because the structure might nolonger match the model and the data will not be serialized and passed on to your controller.
This will have to be handled in your controller logic, but you could easily do this in a base class either to reject the request if the user attempts to provide the fields, or to ignore them, here is an example of a base class handling these rules.
/// <summary>
/// Base controller to support AllowedSelectProperties
/// </summary>
/// <typeparam name="TContext">You application DbContext that this Controller will operate against</typeparam>
/// <typeparam name="TEntity">The entity type that this controller is bound to</typeparam>
/// <typeparam name="TKey">The type of the key property for this TEntity</typeparam>
public abstract class MyODataController<TContext, TEntity, TKey> : ODataController
where TContext : DbContext
where TEntity : class
{
public string AllowedSelectProperties { get; set; }
protected static ODataValidationSettings _validationSettings = new ODataValidationSettings() { MaxExpansionDepth = 5 };
private TContext _db = null;
/// <summary>
/// Get a persistant DB Context per request
/// </summary>
/// <remarks>Inheriting classes can override RefreshDBContext to handle how a context is created</remarks>
protected TContext db
{
get
{
if (_db == null) _db = InitialiseDbContext();
return _db;
}
}
/// <summary>
/// Create the DbContext, provided to allow inheriting classes to manage how the context is initialised, without allowing them to change the sequence of when such actions ocurr.
/// </summary>
protected virtual TContext InitialiseDbContext()
{
// Using OWIN by default, you could simplify this to "return new TContext();" if you are not using OWIN to store context per request
return HttpContext.Current.GetOwinContext().Get<TContext>();
}
/// <summary>
/// Generic access point for specifying the DBSet that this entity collection can be accessed from
/// </summary>
/// <returns></returns>
protected virtual DbSet<TEntity> GetEntitySet()
{
return db.Set<TEntity>();
}
/// <summary>
/// Find this item in Db using the default Key lookup lambda
/// </summary>
/// <param name="key">Key value to lookup</param>
/// <param name="query">[Optional] Query to apply this filter to</param>
/// <returns></returns>
protected virtual async Task<TEntity> Find(TKey key, IQueryable<TEntity> query = null)
{
if (query != null)
return query.SingleOrDefault(FindByKey(key));
else
return GetEntitySet().SingleOrDefault(FindByKey(key));
}
/// <summary>
/// Force inheriting classes to define the Key lookup
/// </summary>
/// <example>protected override Expression<Func<TEntity, bool>> FindByKey(TKey key) => => x => x.Id == key;</example>
/// <param name="key">The Key value to lookup</param>
/// <returns>Linq expression that compares the key field on items in the query</returns>
protected abstract Expression<Func<TEntity, bool>> FindByKey(TKey key);
// PUT: odata/DataItems(5)
/// <summary>
/// Please use Patch, this action will Overwrite an item in the DB... I pretty much despise this operation but have left it in here in case you find a use for it later.
/// NOTE: Default UserPolicy will block this action.
/// </summary>
/// <param name="key">Identifier of the item to replace</param>
/// <param name="patch">A deltafied representation of the object that we want to overwrite the DB with</param>
/// <returns>UpdatedOdataResult</returns>
[HttpPut]
public async Task<IHttpActionResult> Put([FromODataUri] TKey key, Delta<TEntity> patch, ODataQueryOptions<TEntity> options)
{
Validate(patch.GetInstance());
if (!ModelState.IsValid)
return BadRequest(ModelState);
Delta<TEntity> restrictedObject = null;
if (!String.IsNullOrWhiteSpace(this.AllowedSelectProperties))
{
var updateableProperties = AllowedSelectProperties.Split(',').Select(x => x.Trim());
/*****************************************************************
* Example that prevents patch when invalid fields are presented *
* Comment this block to passively allow the operation and skip *
* over the invalid fields *
* ***************************************************************/
if (patch.GetChangedPropertyNames().Any(x => updateableProperties.Contains(x, StringComparer.OrdinalIgnoreCase)))
return BadRequest("Can only PUT an object with the following fields: " + this.AllowedSelectProperties);
/*****************************************************************
* Passive example, re-create the delta and skip invalid fields *
* ***************************************************************/
restrictedObject = new Delta<TEntity>();
foreach (var field in updateableProperties)
{
if (restrictedObject.TryGetPropertyValue(field, out object value))
restrictedObject.TrySetPropertyValue(field, value);
}
}
var itemQuery = GetEntitySet().Where(FindByKey(key));
var item = itemQuery.FirstOrDefault();
if (item == null)
return NotFound();
if (restrictedObject != null)
restrictedObject.Patch(item); // yep, revert to patch
else
patch.Put(item);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ItemExists(key))
return NotFound();
else
throw;
}
return Updated(item);
}
// PATCH: odata/DataItems(5)
/// <summary>
/// Update an existing item with a deltafied or partial declared JSON object
/// </summary>
/// <param name="key">The ID of the item that we want to update</param>
/// <param name="patch">The deltafied or partial representation of the fields that we want to update</param>
/// <returns>UpdatedOdataResult</returns>
[AcceptVerbs("PATCH", "MERGE")]
public virtual async Task<IHttpActionResult> Patch([FromODataUri] TKey key, Delta<TEntity> patch, ODataQueryOptions<TEntity> options)
{
Validate(patch.GetInstance());
if (!ModelState.IsValid)
return BadRequest(ModelState);
if (!String.IsNullOrWhiteSpace(this.AllowedSelectProperties))
{
var updateableProperties = AllowedSelectProperties.Split(',').Select(x => x.Trim());
/*****************************************************************
* Example that prevents patch when invalid fields are presented *
* Comment this block to passively allow the operation and skip *
* over the invalid fields *
* ***************************************************************/
if (patch.GetChangedPropertyNames().Any(x => updateableProperties.Contains(x, StringComparer.OrdinalIgnoreCase)))
return BadRequest("Can only Patch the following fields: " + this.AllowedSelectProperties);
/*****************************************************************
* Passive example, re-create the delta and skip invalid fields *
* ***************************************************************/
var delta = new Delta<TEntity>();
foreach (var field in updateableProperties)
{
if (delta.TryGetPropertyValue(field, out object value))
delta.TrySetPropertyValue(field, value);
}
patch = delta;
}
var itemQuery = GetEntitySet().Where(FindByKey(key));
var item = itemQuery.FirstOrDefault();
if (item == null)
return NotFound();
patch.Patch(item);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ItemExists(key))
return NotFound();
else
throw;
}
return Updated(item);
}
/// <summary>
/// Inserts a new item into this collection
/// </summary>
/// <param name="item">The item to insert</param>
/// <returns>CreatedODataResult</returns>
[HttpPost]
public virtual async Task<IHttpActionResult> Post(TEntity item)
{
// If you are validating model state, then the POST will still need to include the properties that we don't want to allow
// By convention lets consider that the value of the default fields must be equal to the default value for that type.
// You may need to remove this standard validation if this.AllowedSelectProperties has a value
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (!String.IsNullOrWhiteSpace(this.AllowedSelectProperties))
{
var updateableProperties = AllowedSelectProperties.Split(',').Select(x => x.Trim());
/*****************************************************************
* Example that prevents patch when invalid fields are presented *
* Comment this block to passively allow the operation and skip *
* over the invalid fields *
* ***************************************************************/
// I hate to use reflection here, instead of reflection I would use scripts or otherwise inject this logic
var props = typeof(TEntity).GetProperties();
foreach(var prop in props)
{
if (!updateableProperties.Contains(prop.Name, StringComparer.OrdinalIgnoreCase))
{
var value = prop.GetValue(item);
bool isNull = false;
if (prop.PropertyType.IsValueType)
isNull = value == Activator.CreateInstance(prop.PropertyType);
else
isNull = value == null;
if(isNull) return BadRequest("Can only PUT an object with the following fields: " + this.AllowedSelectProperties);
}
}
/***********************************************************************
* Passive example, create a new object with only the valid fields set *
* *********************************************************************/
var sanitized = Activator.CreateInstance<TEntity>();
foreach (var field in updateableProperties)
{
var prop = props.First(x => x.Name.Equals(field, StringComparison.OrdinalIgnoreCase));
prop.SetValue(sanitized, prop.GetValue(item));
}
item = sanitized;
}
GetEntitySet().Add(item);
await db.SaveChangesAsync();
return Created(item);
}
/// <summary>
/// Overwritable query to check if an item exists, provided to assist mainly with mocking
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
protected virtual bool ItemExists(TKey key)
{
return GetEntitySet().Count(FindByKey(key)) > 0;
}
}
That's a cut-down version of the base class that I use in my Applications, just simplifies generic CRUD actions. I apply a bunch of other security trimming and stuff, but for the GET operations I swear by the OnActionExecuting solution, it's faster to execute than anything else I can come up with because it happens before the action is parsed.

Inserting Data into SQLite Database Using C#

I am creating an SQLite Database in Visual Studio with Xamarin in C#.
I should note that this is for android only.
I am trying to make it so I am able to insert data into the SQLite database but I am unsure how.
I have been following this but I'm still unsure.
Here is the method I am trying to create.
/// <summary>
/// Insert a single ping group into the SQLite ping database.
/// </summary>
/// <param name="pingGroup"></param>
public void AddUnsynchronizedPing(PingGroup pingGroup)
{
// TODO: Add the passed ping group parameter into the SQLite database as new/unsynchronized.
if (pingGroup != null)
{
// Add ping group to the database.
// Add pings to the database.
// Maybe one step, maybe done separately.
// If done separately, must set Ping.PingGroupID to ID of original ping group.
}
}
For context, here is the entire class.
namespace BB.Mobile
{
/// <summary>
/// A class to provide a single interface for interacting with all SQLite data operations for stored tracking points.
/// </summary>
///
class DataManager
{
private SQLiteConnection db = null;
public DataManager()
{
if (this.db == null)
{
string dbPath = Path.Combine(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal),
"bb.db3");
db = new SQLiteConnection(dbPath);
db.CreateTable<Ping>();
db.CreateTable<PingGroup>();
}
}
/// <summary>
/// Will compile and return all matching unsynchronized ping data from the SQLite database.
/// </summary>
/// <returns></returns>
public List<PingGroup> GetUnsynchronizedPings()
{
List<PingGroup> unsynchronizedPings = new List<PingGroup>();
// TODO: Retrieve all unsynchronized pings from the SQLite database and return them to the caller.
//var pGroup = db.Get<PingGroup>();
//var pGroupList = db.List<PingGroup>();
var pGroups = db.Table<PingGroup>();
foreach (var pGroup in pGroups)
{
}
return unsynchronizedPings;
}
/// <summary>
/// Insert a single ping group into the SQLite ping database.
/// </summary>
/// <param name="pingGroup"></param>
public void AddUnsynchronizedPing(PingGroup pingGroup)
{
// TODO: Add the passed ping group parameter into the SQLite database as new/unsynchronized.
if (pingGroup != null)
{
// Add ping group to the database.
// Add pings to the database.
// Maybe one step, maybe done separately.
// If done separately, must set Ping.PingGroupID to ID of original ping group.
}
}
/// <summary>
/// Mark all open and unsynchronized pings in the database as synchronized.
/// </summary>
public void SetAllPingsSynchronized()
{
db.DeleteAll<PingGroup>();
db.DeleteAll<Ping>();
}
}
}
Thank you in advance.
To insert the object to sqlite database, you can just use something like:
void InsertPing(Ping p)
{
db.Insert(p);
}
void InsertGroupOfPings(IEnumerable<Ping> pings)
{
db.InsertAll(pings);
}
and to retrieve objects (for example):
List<Ping> GetPings()
{
// I assume here that Ping object has property named Synchronized
return db.Query<Ping>("select * from Ping where Synchronized = 0");
}
The SQLite library creates its tables according to your class definitions, so you can think about the properties of the class as of columns inside the table.

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.

Does it suck or not - Simple DAL with caching using Linq to SQL

I created a simple Caching Data Access Layer that has caching using the Enterprise Library Caching Application Block and also makes use of SQL Query Notification - therefore not supporting any queries which are not valid for query notification.
Background: This was put in place after the application was developed in order to lighten the load on the database and speed up the application. The main use of this DAL is for pulling data that is not expected to change very often such as data in Look Up Tables (presented in drop downs on the UI, etc).
It is mainly used like the following example:
var cachingDal = new CachingDataAccessLayer();
var productTypes = cachingDal.LoadData<ProductType>();
Where ProductType is a Linq to SQL table. I am curious to see what people think of the implementation I came up with and if it is horrible or amazing.
Here's the code. Looking for any suggestions, criticisms, etc etc. Keep in mind I didn't choose the technology and am building on top of an existing system so switching data access stories is not really my call.
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using MyDatabase;
public class CachingDataAccessLayer
{
#region Cache Keys
private const string CacheManagerName = "CachingDataAccessLayer";
#endregion
#region Database
/// <summary>
/// Instantiate new MyDataContext
/// </summary>
/// <returns></returns>
private MyDataContext DatabaseConnection()
{
// instantiate database connection
var database = new MyDataContext(Constants.DatabaseConnectionString);
// set transaction isolation level to read committed
database.ExecuteQuery(typeof(string), "SET TRANSACTION ISOLATION LEVEL READ COMMITTED");
return database;
}
#endregion
#region Generic Data Access with Caching
/// <summary>
/// Calls .Exists on list using predicate and if it evaluates to false, adds records to list using predicate.
/// </summary>
/// <typeparam name="TEntity">Database table</typeparam>
/// <param name="list">List to add records to</param>
/// <param name="predicate">The delagate that defines the conditions of elements to search for.</param>
public void AddRecordsIfNeeded<TEntity>(ref List<TEntity> list, Predicate<TEntity> predicate) where TEntity : class
{
// check if items are in list based on predicate and if not, add them to the list
if (!list.Exists(predicate))
{
list.AddRange(LoadData<TEntity>(predicate.Invoke));
}
}
/// <summary>
/// Retrieve all records of type TEntity from the cache if available with filter Active = true (if Active property exists).<br/>
/// If data is not available in cache go directly to the database.<br/>
/// In addition, sets up query notification and refreshes cache on database change.
/// </summary>
/// <typeparam name="TEntity">Database table to retrieve.</typeparam>
/// <returns>returns List of TEntity</returns>
public List<TEntity> LoadData<TEntity>() where TEntity : class
{
// default filter is no filter
Func<TEntity, bool> predicate = delegate { return true; };
// check for active property
var activeProperty = typeof (TEntity).GetProperty("Active");
// if active property exists and is a boolean, set predicate to filter Active == true
if (activeProperty != null)
if (activeProperty.PropertyType.FullName == typeof (bool).FullName)
predicate = (x => (bool) activeProperty.GetValue(x, null));
// load data & return
return LoadData(predicate);
}
/// <summary>
/// Retrieve all records of type TEntity from the cache if available.<br/>
/// If data is not available in cache go directly to the database.<br/>
/// In addition, sets up query notification and refreshes cache on database change.
/// </summary>
/// <typeparam name="TEntity">Database table to retrieve.</typeparam>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <returns>returns List of TEntity</returns>
public List<TEntity> LoadData<TEntity>(Func<TEntity, bool> predicate) where TEntity : class
{
// default is to not refresh cache
return LoadData(predicate, false);
}
/// <summary>
/// Retrieve all records of type TEntity from the cache if available.<br/>
/// If data is not available in cache or refreshCache is set to true go directly to the database.<br/>
/// In addition, sets up query notification and refreshes cache on database change.
/// </summary>
/// <typeparam name="TEntity">Database table to retrieve.</typeparam>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="refreshCache">If true, ignore cache and go directly to the database and update cache.</param>
/// <returns></returns>
public List<TEntity> LoadData<TEntity>(Func<TEntity, bool> predicate, bool refreshCache) where TEntity : class
{
// instantiate database connection
using (var database = DatabaseConnection())
{
// instantiate the cache
var cache = CacheFactory.GetCacheManager(CacheManagerName);
// get cache key name
var cacheKey = typeof(TEntity).Name;
// if the value is in the cache, return it
if (cache.Contains(cacheKey) && !refreshCache)
// get data from cache, filter it and return results
return (cache.GetData(cacheKey) as List<TEntity>).Where(predicate).ToList();
// retrieve the data from the database
var data = from x in database.GetTable<TEntity>()
select x;
// if value is in cache, remove it
if (cache.Contains(cacheKey))
cache.Remove(cacheKey);
// add unfiltered results to cache
cache.Add(cacheKey, data.ToList());
Logger.Write(string.Format("Added {0} to cache {1} with key '{2}'", typeof(TEntity).Name, CacheManagerName, cacheKey));
// set up query notification
SetUpQueryNotification<TEntity>();
// return filtered results
return data.Where(predicate).ToList();
}
}
#endregion
#region Query Notification
public void SetUpQueryNotification<TEntity>() where TEntity : class
{
// get database connection
var database = DatabaseConnection();
// set up query notification
using (var sqlConnection = new SqlConnection(Constants.DatabaseConnectionString))
{
// linq query
var query = from t in database.GetTable<TEntity>()
select t;
var command = database.GetCommand(query);
// create sql command
using (var sqlCommand = new SqlCommand(command.CommandText, sqlConnection))
{
// get query parameters
var sqlCmdParameters = command.Parameters;
// add query parameters to dependency query
foreach (SqlParameter parameter in sqlCmdParameters)
{
sqlCommand.Parameters.Add(new SqlParameter(parameter.ParameterName, parameter.SqlValue));
}
// create sql dependency
var sqlDependency = new SqlDependency(sqlCommand);
// set up query notification
sqlDependency.OnChange += sqlDependency_OnChange<TEntity>;
// open connection to database
sqlConnection.Open();
// need to execute query to make query notification work
sqlCommand.ExecuteNonQuery();
}
}
Logger.Write(string.Format("Query notification set up for {0}", typeof(TEntity).Name));
}
/// <summary>
/// Calls LoadData of type TEntity with refreshCache param set to true.
/// </summary>
/// <typeparam name="TEntity">Database table to refresh.</typeparam>
void RefreshCache<TEntity>() where TEntity : class
{
// refresh cache
LoadData<TEntity>(delegate { return true; }, true);
}
/// <summary>
/// Refreshes data in cache for type TEntity if type is Delete, Insert or Update.<br/>
/// Also re-sets up query notification since query notification only fires once.
/// </summary>
/// <typeparam name="TEntity">Database table</typeparam>
void sqlDependency_OnChange<TEntity>(object sender, SqlNotificationEventArgs e) where TEntity : class
{
var sqlDependency = sender as SqlDependency;
// this should never happen
if (sqlDependency == null)
return;
// query notification only happens once, so remove it, it will be set up again in LoadData
sqlDependency.OnChange -= sqlDependency_OnChange<TEntity>;
// if the data is changed (delete, insert, update), refresh cache & set up query notification
// otherwise, just set up query notification
if (e.Info == SqlNotificationInfo.Delete || e.Info == SqlNotificationInfo.Insert || e.Info == SqlNotificationInfo.Update)
{
// refresh cache & set up query notification
Logger.Write(string.Format("sqlDependency_OnChange (Info: {0}, Source: {1}, Type: {2}). Refreshing cache for {3}", e.Info, e.Source, e.Type, typeof(TEntity).Name));
RefreshCache<TEntity>();
}
else
{
// set up query notification
SetUpQueryNotification<TEntity>();
}
}
#endregion
}
Personally, I'd suggest using the Repository pattern, where you have an IRepository.
Then, in real terms you could use an IoC container to provide your app with a CacheRepository for some static types that uses the caching system in the first instance and either automatically delegates on to a LinqToSqlRepository where data isn't found, or returns null and allows you to deal with populating the cache yourself.
If the data isn't expected to change very much and it's used for the UI such as for drop-downs etc., why not cache the data on client's machine? We did this for an application we built a while back. We cached almost all of our "look-up" type data in files on the client machine and then built a mechanism to invalidate the data when it was modified in the database. This was very fast and worked well for us.
BTW, are you aware that L2S does it's own caching?

Categories

Resources