Wednesday, 2 April 2014

Unit of work


-------------------------------------------------------------------------------------
public interface IUnitOfWork : IDisposable
   {
       ICourseRepository Courses { get; }
       IAuthorRepository Authors { get; }
       int Complete();
   }


-------------------------------------------------------------------------------------
public class UnitOfWork : IUnitOfWork
   {
       private readonly PlutoContext _context;
 
       public UnitOfWork(PlutoContext context)
       {
           _context = context;
           Courses = new CourseRepository(_context);
           Authors = new AuthorRepository(_context);
       }
 
       public ICourseRepository Courses { getprivate set; }
       public IAuthorRepository Authors { getprivate set; }
 
       public int Complete()
       {
           return _context.SaveChanges();
       }
 
       public void Dispose()
       {
           _context.Dispose();
       }
   }


public interface IRepository<TEntitywhere TEntity : class
    {
        TEntity Get(int id);
        IEnumerable<TEntity> GetAll();
        IEnumerable<TEntity> Find(Expression<Func<TEntitybool>> predicate);
 
        // This method was not in the videos, but I thought it would be useful to add.
        TEntity SingleOrDefault(Expression<Func<TEntitybool>> predicate);
 
        void Add(TEntity entity);
        void AddRange(IEnumerable<TEntity> entities);
        
        void Remove(TEntity entity);
        void RemoveRange(IEnumerable<TEntity> entities);
    }

-------------------------------------------------------------------------------------
public interface ICourseRepository : IRepository<Course>
   {
       IEnumerable<Course> GetTopSellingCourses(int count);
       IEnumerable<Course> GetCoursesWithAuthors(int pageIndex, int pageSize);
   }

-------------------------------------------------------------------------------------

public class Repository<TEntity> : IRepository<TEntitywhere TEntity : class
    {
        protected readonly DbContext Context;
 
        public Repository(DbContext context)
        {
            Context = context;
        }
 
        public TEntity Get(int id)
        {
            // Here we are working with a DbContext, not PlutoContext. So we don't have DbSets 
            // such as Courses or Authors, and we need to use the generic Set() method to access them.
            return Context.Set<TEntity>().Find(id);
        }
 
        public IEnumerable<TEntity> GetAll()
        {
            // Note that here I've repeated Context.Set<TEntity>() in every method and this is causing
            // too much noise. I could get a reference to the DbSet returned from this method in the 
            // constructor and store it in a private field like _entities. This way, the implementation
            // of our methods would be cleaner:
            // 
            // _entities.ToList();
            // _entities.Where();
            // _entities.SingleOrDefault();
            // 
            // I didn't change it because I wanted the code to look like the videos. But feel free to change
            // this on your own.
            return Context.Set<TEntity>().ToList();
        }
 
        public IEnumerable<TEntity> Find(Expression<Func<TEntitybool>> predicate)
        {
            return Context.Set<TEntity>().Where(predicate);
        }
 
        public TEntity SingleOrDefault(Expression<Func<TEntitybool>> predicate)
        {
            return Context.Set<TEntity>().SingleOrDefault(predicate);
        }
 
        public void Add(TEntity entity)
        {
            Context.Set<TEntity>().Add(entity);
        }
 
        public void AddRange(IEnumerable<TEntity> entities)
        {
            Context.Set<TEntity>().AddRange(entities);
        }
 
        public void Remove(TEntity entity)
        {
            Context.Set<TEntity>().Remove(entity);
        }
 
        public void RemoveRange(IEnumerable<TEntity> entities)
        {
            Context.Set<TEntity>().RemoveRange(entities);
        }
    }

-------------------------------------------------------------------------------------
public class PlutoContext : DbContext
{
    public PlutoContext()
        : base("name=PlutoContext")
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
 
    public virtual DbSet<Author> Authors { getset; }
    public virtual DbSet<Course> Courses { getset; }
    public virtual DbSet<Tag> Tags { getset; }
 
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new CourseConfiguration());
    }

-------------------------------------------------------------------------------------
public class UnitOfWork : IUnitOfWork
   {
       private readonly PlutoContext _context;
 
       public UnitOfWork(PlutoContext context)
       {
           _context = context;
           Courses = new CourseRepository(_context);
           Authors = new AuthorRepository(_context);
       }
 
       public ICourseRepository Courses { getprivate set; }
       public IAuthorRepository Authors { getprivate set; }
 
       public int Complete()
       {
           return _context.SaveChanges();
       }
 
       public void Dispose()
       {
           _context.Dispose();
       }
   }

Friday, 3 May 2013

EF casting nchar to nvarchar

Weird glitch to watch out for in EF codefirst approach, where a string property defined in model which SQL Server automatically presumes is an nvarchar. But which actually is a varchar in the database. Since these are coercible, Entity Framework decided to coerce the type under the covers....

Performance Eater: Casting nchar to nvarchar
Performance Eater: Casting nchar to nvarchar

Tuesday, 16 April 2013

Detecting asp.net session timeouts

A common requirement i get in alot of asp.net applications to automatically redirected to a login page or a home page when my ASP.Net session times out and the user tries to hit a page in the website.

Before i mention the code , it is important to note that every asp.net application you install on your IIS server gets the same session cookie id by default : a cookie called:ASP.NET_SessionId

To establish this , go to IIS , highlight your website , ensure that Features view is on and click on the Session State icon.



Go to the Cookie settings section and you'll se that your webapplication has a cookie name/id of ASP.NET_SessionId. If you install another application , it will get the same id.




So in order to detect when the session has ended you can override the onInit method in your master page and add the following code:

/// <summary>

/// Check for the session time out

/// </summary>

/// <param name="e"></param>

protected override void OnInit(EventArgs e)
{

base.OnInit(e);

if (Context.Session != null)
{

//check whether a new session was generated

if (Session.IsNewSession)
{

//check whether a cookies had already been associated with this request

HttpCookie sessionCookie = Request.Cookies["ASP.NET_SessionId"];

if (sessionCookie != null)
{

string sessionValue = sessionCookie.Value;

if (!string.IsNullOrEmpty(sessionValue))
{

// we have session timeout condition!
Response.Redirect(
"MyhomePage.aspx");
}


Session Isolation

This is all well and good , but seeing as every .NET application gets the same cookie id on the same iis box , it is clear that this would cause unpredictable results in the scenario that you would have two or more .NET applications installed on the same server and want to detect the session timeouts in each.

In order to do this we would need to ensure session isolation. One solution to this would to put each .NET application in a different app pool. This would create the isolation needed to allow thier sessions to work independantly to each other.

If this isn't an option , another way to do it is to specify a unique session cookie Id for each .NET application in their web.configs. This can be either done manually in the web.config or can be programatically achived by Creating customized Setup projects in Visual Studio 2008/2010.

To Manually add a unique cookie to your web.config , add the cookieName attribute to your sesssionstate element. It's good practice to give this your application name. If you have multiple versions of the sample application installed on your iis box you can configure this via the a customized setup project to create the cookie based on application name and version so you get a unique cookieName.

sessionState mode="InProc" cookieName="MyCompany.MyFinancialWebsite" timeout="15" />


/// <summary>

/// Handles the Start event of the Session control.

/// </summary>

/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>

protected void Session_Start(object sender, EventArgs e)
{


SessionStateSection sessionStateSection =
(System.Web.Configuration.
SessionStateSection)

ConfigurationManager.GetSection("system.web/sessionState");

string cookieName = sessionStateSection.CookieName;

//Detect session timeout and re-direct to home page

string request_cookies = Request.Headers["Cookie"];

if ((null != request_cookies) && (request_cookies.IndexOf(cookieName) >= 0))
{


////cookie existed, so this new one is due to timeout.

////Redirect the user to the default page
Response.Redirect(
"AccountSearch.aspx?Timeout=true");
}


}

Tuesday, 9 April 2013

EF5 Performance Considerations

Over the past few weeks the EF team has been putting together a whitepaper that talks about the performance considerations developers should take when using Entity Framework. Performance is one critical aspect of developing modern applications, and this document will help developers make informed design decisions and get the most out of their applications when using the Entity Framework 5 (and also EF 4).

http://blogs.msdn.com/b/adonet/archive/2012/04/05/ef5-performance-considerations.aspx

New EF5 Pluralsight Course

Pluralsight have just posted a new Entity Framework 5 course by EF Expert Julie Lerman .
This course provides an introduction to using Entity Framework 5 with Visual Studio 2012
Check it out !

Saturday, 16 March 2013

Non Ajax solution for disabling a button after click for full .NET postbacks

It's that old chestnut where you want to disable a button after the user clicks it to prevent them potentially clicking it again and accidental calling the server side event twice. This is especially an issue for longer running tasks .

This may sound really easy to do at first , just disable it with javasctip right ? But when you try this, you'll find that with disabling a submit button on the client side will cancel the browser’s submit, and thus the postback. Not what you want to happen!

There are a few methods going around to do this , but i find this one the easiest , kick back to Encosia where i first found this approach.

This method is to use the OnClientClick and UseSubmitBehavior properties of the button control.

<asp:Button runat="server" ID="BtnSubmit"
  
OnClientClick="this.disabled = true; this.value = 'Submit in progress...';"
  
UseSubmitBehavior="false"
  
OnClick="BtnSubmit_Click"
  
Text="Click to Submit" />


OnClientClick allows you to add client side OnClick script. In this case, the JavaScript will disable the button element and change its text value to a progress message. When the postback completes, the newly rendered page will revert the button back its initial state without any additional work

Sunday, 3 March 2013

Column Level Database Encryption using Symmetric Keys

Recently i needed to encrypt a column on (a password field) in a table in SQL Server 2008 database. After a bit of research and reading some great articles by Pinal Dave and Laurentiu Cristofor i decided Symmetric keys were the best approach for what i needed to achieve.

Encryption using Symmetric keys are one of the recommended methods of column level encryption in in SQL Server 2005/2008 for a number of reasons:



Advantages Of Symmetric Keys Encryption


  • Performance.Symmetric key encryption is known to be much faster and stronger than their asymmetric counterpart. It uses less overhead on system resources. For some examples and timings between Symmetric and Asymmetric key encryption check out Brian Kelley
  • Personally i find the symmeteric key approach very easy to work with.
  • Easy to backup and restore your database without alot of re-work or data loss , ill talk about this later on in the article.

When a symmetric key is created, the symmetric key must be encrypted by using at least one of the following: certificate, password, symmetric key, asymmetric key, or PROVIDER. The key can have more than one encryption of each type. In other words, a single symmetric key can be encrypted by using multiple certificates, passwords, symmetric keys, and asymmetric keys at the same time.

Simple Encryption Example

Here is a simple example using the Master key to encrypt the Certificates and Keys in a database.

/* Create Database Master Key */
USE AliciaEncryptionTest
GO
CREATE MASTER KEY ENCRYPTION
BY PASSWORD 'MyTestPassword'
GO


Now, you'll need a certificate with which you will encrypt your symmetric key. Certificates are used to safeguard encryption keys, which are used to encrypt data in the database.

/* Create Encryption Certificate */
USE AliciaEncryptionTest
GO
CREATE CERTIFICATE EncryptTestCert
WITH SUBJECT 'MyEncryptionDatabaseCert'
GO

Once you have your certificates, you can create your key. The symmetric key can be encrypted by using various options such as certificate, password, symmetric key, and asymmetric key.
We can use many types of algorithm while creating Symmetric keys like DES, TRIPLE_DES, TRIPLE_DES_3KEY, AES_128, AES_192, AES_256 etc.

You should try to use the most secure algorithm you can, which is AES_256 in SQL Server 2012. It’s the same back to SQL Server 2005. You should avoid the RC4 algorithms, since they are not terribly secure. Even the DES ones you might avoid, but do some research to understand if you have a need to use anything less than AES_256.

/* Create Symmetric Key */
USE AliciaEncryptionTest
GO

CREATE SYMMETRIC KEY TestTableKey
WITH ALGORITHM AES_256
BY CERTIFICATE EncryptTestCert
GO


It's as simple as that. You're key is now created and ready to use. To use this key in a simple example , create a table and add a column of type varbinary which will be the column you wish to encrypt.

USE EncryptTest
GO
CREATE TABLE TestTable(FirstCol INT, EncryptSecondCol VARBINARY(256))
GO
Before you can use your symmetric key, you have to open it. The symmetric key remains open for the life of the session. It is good practice to close your key after use as well. Here's how you open and close keys.

/* Update binary column with encrypted data created by certificate and key */
USE AliciaEncryptionTest
GO

OPEN SYMMETRIC KEY TestTableKey
DECRYPTION BY CERTIFICATE EncryptTestCert

INSERT
INTO TestTable VALUES (1,ENCRYPTBYKEY(KEY_GUID('TestTableKey'),'NewPassword' ))

GO

/* Close symmetric key */
CLOSE SYMMETRIC KEY TestTableKey ;
Authorized user can use the decryptbykey function to retrieve the original data from the encrypted column. If Symmetric key is not open for decryption, it has to be decrypted using the same certificate that was used to encrypt it. Decryption uses the same method that was used for encrypting it. Because of the same reason, we are using the same certificate for opening the key and making it available for use.

/* Decrypt the data of the SecondCol */
USE AliciaEncryptionTest
GO

OPEN SYMMETRIC KEY TestTableKey
DECRYPTION BY CERTIFICATE EncryptTestCert
SELECT CONVERT(VARCHAR(50),DECRYPTBYKEY(EncryptSecondCol)) AS DecryptSecondCol
FROM TestTable
GO
CLOSE SYMMETRIC KEY TestTableKey ;
GO

/* Clean up database */
USE AliciaEncryptionTest
GO

CLOSE SYMMETRIC KEY TestTableKey
GO

DROP SYMMETRIC KEY TestTableKey
GO

DROP CERTIFICATE EncryptTestCert
GO

DROP MASTER KEY
GO

Backing up and restoring your database to a different server

Often you have to backup your database and restore it to a different server. Sometimes you have data already in an encrypted table and you need to be able to decrypt it from the new server. It is important to note that you cannot backup a symmetric key from one database and copy it to another.

When you create a backup, the symmeteric key is saved as part of the backup, so therefore they are available upon restore. However if the symmeteric  key was ecrypted using a certificate, that may not be available if the restore is to a different box.

Certificates are also stored in the database, so they should be available with the symmetric keys. You don't loose the certificates if you move the database to another server. The only thing you may need to do after restoring a database on a different server, is to restore the SMK encryption of the DbMK. For this, you need to execute the following statements in the database after you restored it:

OPEN MASTER KEY DECRYPTION BY PASSWORD = 'DbMK password';ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY;
Other than this, you don't need to do anything special to be able to work with the encrypted data like you worked on the original server.