Category: full

Usual Methods to transfer data from Page To Page in ASP.NET MVC

Preamble:

In ASP.NET ( like in PHP and other Web frameworks) there are 2 clear entities: Server ( code on the WebServer ) and Client( the HTML interpreted by the browser and javascript).

Server and Client shares same cookies – means Client and Client both can read and write cookies.

Transfer from the Client to Server happens when

a) you click a link : the information to transfer is query string . That means, http://…/a?x=y&a=b will send information y ( associated to key x) and b( associated to key a). This is called a GET

b) you press a submit button to send a FORM : the information is values of select and input. This is called a POST.

c) you send information via javascript ( including AJAX) . Usually this can involve a PUT, a GET, or other ( see REST ).

d) Creating/Modifying and send cookies. The sending happens automatically by the browser .

Transfer from the Server to Client

a)sending text(HTML)/binary data. . The interpretation is done by the browser( how to display html, how to display send file …)

b) Creating/Modifying and send cookies . Browser will do automatically this.

ASP.NET WebForms way:

For ASP.NET Webforms the modalities to transfer are detailed by Peter Bromberg , http://www.eggheadcafe.com/tutorials/asp-net/e653f028-01fb-4d0e-843b-058deae562a2/eight-different-ways-to-transfer-data-from-one-page-to-another-page.aspx .

ASP.NET MVC way:

I want to discuss from ASP.NET MVC perspective. In MVC we have 2 distinct objects: VIEW and ACTION. Both happens to run on the Server .

  • The ACTION can return a VIEW or ( or a redirect to) another ACTION or simply a FILE
  • The VIEW processes a Model ( and a ViewBag/ViewData) and sends the text( HTML) data to the Client .

Instead of PAGES , we will discuss of VIEWS – because the VIEWS sends HTML data to the Client.

So, to transfer data between View1 to View2 in MVC is reduced to this:

a) Page1 transfer data to the server ACTION1( by a,b,c,d methods in the Preamble )

b) The Action receives the values as his parameters ( by binding) and can do this:

b1) Return a different View ( using some logic :

if( a )

return View1(Model1);

else

return View2(Model1);

b2) Returning a Redirect to ACTION2 ( that return View2) or simply return the result of this action

return RedirectToAction(Action2(<parameters>)); //Used in Post/Request/GET, http://en.wikipedia.org/wiki/Post/Redirect/Get

return Action2(<parameters>);

Resuming: Transfer betweem PAGE to PAGE in ASP.NET MVC is really transfering from ACTION to ACTION , besides the cookie that can be transferred directly by the browser.

9 Modalities to transfer data from Page to Page in ASP.NET MVC

Enough theory, let’s do some code. We have a Model to transfer named ModelTransfer

public class ModelTransfer
    {
        public int Age { get; set; }
        public string Name { get; set; }


    }

We have the first View1( Index) and a second View2(Transfer) that will server as an example. Also, we will have the more ACTIONS – one for each example of transfer – all are using the TRANSFER action as an ultimate resort do see the View.

Method1 : Transfer directly to the second View/Action .

<a href='@Url.Action("Transfer", new { Age = 42, Name = "Andrei Ignat" })'>click me</a>
public ActionResult Transfer(ModelTransfer m)

Method2 Index sends POST data to a [HttpPost] Index action, that performs some calculations and return a redirect.Usefull in PRG

@using (Html.BeginForm()) { 
<input type="text" id="Age" name="Age" value="42" />
<input type="text" id="Name" name="Name"  value="Andrei Ignat"/>
<input type="submit" value="Click me" />
}

 [HttpPost]
        public ActionResult Index(ModelTransfer m)
        {
            //save to the database the data 

            //this is for transferring alert data - such an "Completed saving" message to the user 
            TempData["displayalert"] = " this is from Index POST action!";
            //used in PRG 
            return RedirectToAction("Transfer", new ModelTransfer() { Age = m.Age, Name = m.Name });            
        }

Method3: No data send. The ServerAction just make some data to be transferred to the Transfer view, by TempData

<a href='@Url.Action("ServerAction")'>click me</a>
 public ActionResult ServerAction()
        {
            //You can put also into the Session / Application /Cache depending on your specifications
            TempData["MyModel"]=new ModelTransfer(){ Age = 42, Name = "Andrei Ignat"};
            TempData["displayalert"] = "this is from Server action!";
            
            return RedirectToAction("Transfer");
        }

Method4: No data send. The ServerAction just make some data to be transferred to the Transfer view, by Cache

Method5: No data send. The ServerAction just make some data to be transferred to the Transfer view, by Session

Method6: No data send. The ServerAction just make some data to be transferred to the Transfer view, by Application

Method7: No data send. The ServerAction just make some data to be transferred to the Transfer view, by HttpContext Items

Method8: By Cookies

<a href='@Url.Action("TransferCookies")'>click me</a>
 HttpCookie cook = new HttpCookie("Transfer");
            //usually you put here more , but now I do not want to interfere with other methods
            cook.Expires = DateTime.Now.AddSeconds(1);
            cook.Value = "from transfer cookies";
            Response.Cookies.Add(cook);
            return RedirectToAction("Transfer");

Method9: By Javascript /Ajax.
It is an entire post by itself and you can see here:
http://msprogrammer.serviciipeweb.ro/2011/12/05/jquery-ajax-request-and-mvcdetailed/

Summary

In this post you have seen 9 methods to transfer data in MVC. As a bonus, the page dispolays also a message with Javascript( usefull for messaging like “Data Saved to database” messages to the user.
The code source you will find here:

Transfer Data Page to Page
It is made with Razor and MVC3 – but you can replace Razor with aspx and MVC3 with MVC2 also.

If you think I can improve this post, please leave some comment.

Notes:

I used here hard coding values. Please learn about T4MVC and Html.EditorFor !

To learn more about ASP.NET MVC visit http://asp.net/mvc.

Default TempDataProvider is based on Session. There is one more , based on cookies.

Please do the exercises to gain self knowledge about MVC

Caching in .NET

In every application you have some data that is more read-more, write-once or twice. For example you can have the list of Cities of a country, the list of Countries of the world or list of exchange currency. This data is modified rarely. Also, you can have data that is not very sensitive to be real-time , such as the list of invoices for the day.
In .NET 3.5 you have several options
1. ASP.NET caching – and implementing in other applications with HttpRuntime  ( even if MS says “The Cache class is not intended for use outside of ASP.NET applications”)

2. Enterprise caching block : hard to configure

3. memcached , velocity, sharedcache and other third party providers – that comes with their options and configuration

In .NET 4.0 you have a new kid : objectcache and , more important , an implementation : MemoryCache

http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache%28v=VS.100%29.aspx

What is very good is that now you can cache in Memory what do you want – and apply easily to your Business Layer. More, the object is a singleton for the application – that is even better (see the test on the final of the post)

What it is missing is an easy implementation for List and an implementation to remove data after a defined time.

So I decided to do my implementation for that (ok, it is wrong to have both implementations in a single class – but you can separate easily )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Caching;

namespace CachingData{

    /// <summary>
    /// List<int> i = new List<int>() { 1, 10, 100 };
            //CacheData_List<List<int>, int> data = new CacheData_List<List<int>, int>(2);
            //data.Add(i);
            //Assert.AreEqual(3, data.Items().Count, "must be 3");
            //data = new CacheData_List<List<int>, int>();
            //Assert.AreEqual(3, data.Items().Count, "must be 3");
            //Assert.IsTrue(data.ContainsData, "must have data");
            //Thread.Sleep(1000 * 3);
            //Assert.IsFalse(data.ContainsData, "must not have data");
    /// </summary>
    /// <typeparam name="T">and generic ILIST </typeparam>
    /// <typeparam name="U"></typeparam>
    public class CacheData_List<T, U>
        where T:class,IList<U>, new()

    {
        /// <summary>
        /// use this for adding in cache
        /// </summary>
        public event EventHandler RemovedCacheItem;

        private System.Timers.Timer timerEvent;
        private MemoryCache buffer;
        private int TimeToLiveSeconds;

        private DateTimeOffset dto;
        private string Key;
        /// <summary>
        /// default constructor - cache 600 seconds = 10 minutes
        /// </summary>
        public CacheData_List()
            : this(600)
        {
        }
        /// <summary>
        /// constructor cache the mentioned TimeSeconds time
        /// </summary>
        /// <param name="TimeSeconds">value of time for cache</param>
        public CacheData_List(int TimeSeconds)
        {
            TimeToLiveSeconds = TimeSeconds;
            timerEvent=new System.Timers.Timer(TimeToLiveSeconds * 1000);
            timerEvent.AutoReset = true;
            timerEvent.Elapsed += new System.Timers.ElapsedEventHandler(timerEvent_Elapsed);
            dto = new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
            Key = typeof(T).ToString();
            buffer = MemoryCache.Default;
        }

        void timerEvent_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (RemovedCacheItem != null)
            {
                RemovedCacheItem(this, EventArgs.Empty);
            }
        }
        /// <summary>
        /// remove item from cache
        /// </summary>
        public void Remove()
        {
            if (buffer.Contains(Key))
            {
                buffer.Remove(Key);

            }
            dto=new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
        }
        /// <summary>
        /// add multiple items to cache
        /// </summary>
        /// <param name="items">items to add to the cache</param>
        public void Add(T items)
        {

            if (buffer.Contains(Key))
            {
                T data = Items();
                foreach (var t in data)
                {
                    items.Add(t);
                }
                buffer.Remove(Key);
            }
            buffer.Add(Key, items, dto);
        }
        /// <summary>
        /// add a item to the IList of the cache
        /// </summary>
        /// <param name="item">an item to add</param>
        public void AddItem(U item)
        {

            T data=new T();
            if (buffer.Contains(Key))
            {
                data = buffer.Get(Key) as T;
                buffer.Remove(Key);
            }

            data.Add(item);
            buffer.Add(Key, data,dto);
        }
        /// <summary>
        /// usefull if you do not intercept the removed event
        /// </summary>
        public bool ContainsData
        {
            get
            {
                return buffer.Contains(Key);
            }

        }
        /// <summary>
        /// retrieve items
        /// </summary>
        /// <returns></returns>
        public T Items()
        {
            if (!buffer.Contains(Key))
                return null;

            return buffer.Get(Key) as T;
        }
    }
}

Please note that the test for usage is in the summary :

</pre>
List i = new List() { 1, 10, 100 };
CacheData_List <List<int>, int> data = new CacheData_List<List<int>, int>(2);
data.Add(i);
Assert.AreEqual(3, data.Items().Count, "must be 3");
data = new CacheData_List<List<int>, int>();
Assert.AreEqual(3, data.Items().Count, "must be 3");
Assert.IsTrue(data.ContainsData, "must have data");
Thread.Sleep(1000 * 3);
Assert.IsFalse(data.ContainsData, "must not have data");

You can download the file from

http://msprogrammer.serviciipeweb.ro/wp-content/uploads/2010/05/CachingData.zip

(Last Note : for synchonization maybe it was better to lock on readerwriterlockslim

Intercept errors

Errors interception and rising

Description

We will speak here about the errors raised by external conditions (bugs) and the errors rose by the application.

There is not application without bugs. The bugs are not desired for an application – but programmers are human beings and, by consequence, they cannot verify every possible path that go an application to the failure. Maybe the space on hard is too little, other time the network between database and application is broken – there are many conditions to bring failure to an application. And you have to manage priority between

· repairing bugs

· evolving the application

· Resolving failure cases.

The errors raised by the application are usually logical errors, like the fact that a birthday date for a person cannot be tomorrow. Sometimes you will intercept errors from other components and raise your own error (like the fact that a component should have a unique name – you will intercept the index failure raised by your database and then raise your own error).

How to intercept error in applications

We will discuss here how and where to intercept errors. There are two principles that I guide my interception of errors:

1. Occam’s razor : in components(business layer, repository) intercept only the errors that you are sure to know what to do with (such as an ID is missing from a database). Usually here you can raise your own exception and let the GUI handle it. In

2. In GUI layer intercept all exception and , if possible, suggest to the user an alternative way to do.You must also log the error in order to can be retrieved later.

Please read the logging and instrumentation to see a common way to describe the path that a error has been flow through the application

Examples

First example is how to intercept an error

Second will be how to intercept and raise own errors

Third will be about intercepting errors in a Console application

1)We will first intercept an error and write a custom message for this error .

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.SqlClient;

namespace exceptionintercept

{

class Program

{

static void Main(string[] args)

{

using (SqlConnection sc = new SqlConnection())

{

sc.ConnectionString = "Data Source=(local);Initial Catalog=adaad!@#$%^;Trusted_Connection=true";

try

{

sc.Open();

}

catch (SqlException ex)

{

if (ex.Number == 2)

{

Console.WriteLine("no database connection : “+ ex.Message);

return;

}

throw;

}

}

}

}

}

As you see we will intercept only the SqlException and put the custom error message only if error message number for the SqlException is 2 – no network access. Usually it is not a good idea to show your connection string in the output shown to the user.

Download project from http://msprogrammer.serviciipeweb.ro/wp-content/uploads/exception.zip

2) Intercept and raise error

We will do now a more advanced interception of connection : we will see if the machine that has the database answers to the ping. If yes, probably only the database is down , not the PC or the connection.

public void VerifyConnection(string MyConnection)

{

using (SqlConnection sc = new SqlConnection())

{

sc.ConnectionString = MyConnection;

try

{

sc.Open();

}

catch (SqlException ex)

{

//TODO : log the exception

Ping p = new Ping();

try

{

PingReply pr = p.Send(sc.DataSource);

}

catch (PingException)

{

//TODO : log the exception

throw new PCException(sc.DataSource, ex);

}

throw new BasicDatabaseException(sc.DataSource,ex);

}

}

}

3) Any application should intercept globally errors, in order to log / save state if there is something that works not well and it is not handled.

static void Main(string[] args)

{

System.AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

int i = 1;

i = 1 / (i - 1);

}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)

{

//TODO : log

Console.WriteLine("from program : unexpected error occured " + e.ExceptionObject);

}

Download project from http://msprogrammer.serviciipeweb.ro/wp-content/uploads/exception.zip

TODO

intercept global errors in WinForms, ASP.NET , WPF, Silverlight application

Other resources

ELMAH – intercept ASP.NET errors , http://code.google.com/p/elmah/

Logging : http://msprogrammer.serviciipeweb.ro/2010/04/19/logging-and-instrumentation/

Logging and instrumentation

Why

There are at least two reasons for an application to register what tfhe user do.

The first one and the most important is to see what is happening when a user has an error: what have been done, on which path did he go and what additional data(method parameters, usually) do you need for reproducing the bug.

The second one is to provide the application a way to record in-obtrusive messages for same actions that may seems not so right(check the event log for your computer for more examples 😉 )

Requirements for a logging system

The logging system should be:

1. Robust – if it can not write the message, it should not fail the entire app

2. Multi-write-data : it can write easily to multiple systems(such as databases, files on disk, send emails and so on)

3. Flexibility : the configuration of the logging system should be easy to modify. More, the modifications should be applied and “re-loaded” without re-compiling or re-starting the application

An implementation

For the implementation I will use log4net , http://logging.apache.org/log4net/ that it is satisfies all three conditions.

We will do a console application that sends a random error

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace ConsoleDemo1

{

class Program

{

static void Main(string[] args)

{

long ticks = DateTime.Now.Ticks;

FirstFunction(ticks);

}

static void FirstFunction(long i)

{

if (i % 2 == 0)

{

throw new ArgumentException("from first function");

SecondFunction(i);

}

static void SecondFunction(long i)

{

if (i % 2 == 1)

{

throw new ArgumentException("from second function");

}

}

}

}

As you see this application will have an error no matter if the ticks are even or odd. Download project from here : http://msprogrammer.serviciipeweb.ro/wp-content/uploads/loggingDemo.zip

Now we will see how the log4net writes data and error to a physical storage, in order to can be retrieved later.

Download log4net, add reference to it and make the following 4 steps

1. add a config file (I will name it log4net.config ) and in properties put “Copy to output Directory” to “Copy always” .

clip_image002[4]

Examples of log4net config files you will find everywhere on internet . If you look at the project you will see a bunch of “appenders” : ConsoleAppender, RollingLogFileAppender , SmtpAppender . The appender appends the log to the storage provided (Console, File, Email ). You will find a list of appenders at http://logging.apache.org/log4net/release/sdk/log4net.Appender.html and, if you do not found some appender you can wrote your own – just look at the source code.

For this application I want to use just ConsoleAppender and RollingFileAppender

<root>

<level value=”DEBUG” />

<appender-ref ref=”ConsoleAppender” />

<appender-ref ref=”RollingLogFileAppender” />

</root>

2. In order to see the file, put


log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo("log4net.config"));

(for asp.net application ,put


log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(Server.MapPath("~/log4net.config")));

)

3. Add a variable to log the errors :


private static readonly log4net.ILog _logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

4. Add a try/catch to log errors :

try

{

FirstFunction(ticks);

}

catch (Exception ex)

{

if (_logger.IsErrorEnabled)

{

_logger.Error("see an error!", ex);

}

throw;

}

Now, if you run the ConsoleDemoLog4net project, then you will see how to exception is logged twice and you will find the currentlog.txt in the same folder as your application executable.

Automatically instrument an application(dll, exe, asp.net)

This was pretty good – but what about putting a log to every method to see where the application flow has been gone and with which arguments?

You can do this with postsharp / log4postsharp. Postsharp is … Log4Postsharp is …

Let’s make the application do this automatically.

We download Postsharp 1.0 (not 1.5!) from http://www.softpedia.com/progDownload/PostSharp-Download-114994.html (you can found a more good paid version at http://www.sharpcrafters.com/downloads/ )

Now we will do the following :

1. Add the log4net.config from the previous project

2. Add log4net , PostSharp.Public and PostSharp reference

3. Add to the main just:

log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo("log4net.config"));

Do NOT add the log4net code to intercept!

4. Modify AssemblyInfo.cs and put

using Log4PostSharp;

[assembly: Log(AttributeTargetTypes = "*", EntryLevel = LogLevel. Error, EntryText = "postsharp :entering {signature} {paramvalues}", ExitLevel = LogLevel. Error, ExceptionLevel = LogLevel.Error, ExitText = "postsharp :exit {signature} {paramvalues} =&gt; {returnvalue}", ExceptionText = "postsharp : error in {signature} ")]

5. Add a text file named <yourprojectname>.psproj (in this case, ConsoleDemoPostSharp.psproj ) with the following content:

<?xml version=”1.0″ encoding=”utf-8″ ?>

<Project xmlns=”http://schemas.postsharp.org/1.0/configuration”>

<SearchPath Directory=”bin/{$Configuration}”/>

<SearchPath Directory=”{$SearchPath}” />

<SearchPath Directory=”lib” />

<Tasks>

<AutoDetect />

<Compile TargetFile=”{$Output}” IntermediateDirectory=”{$IntermediateDirectory}” CleanIntermediate=”false” />

</Tasks>

</Project>

6. Edit by hand the csproj file and add this :

<PropertyGroup>

<DontImportPostSharp>True</DontImportPostSharp>

<PostSharpDirectory> ..\libs\ postsharp\</PostSharpDirectory>

<PostSharpUseCommandLine>True</PostSharpUseCommandLine>

</PropertyGroup>

<Import Project="$(PostSharpDirectory)PostSharp.targets" Condition=" Exists('$(PostSharpDirectory)PostSharp.targets') " />

7. If there is a screen to ask you about a project modification, please tell “Load project normally”

So now , when it’s compiling , it says :

“D:\programe\youtube\loggingDemo\libs\postsharp\PostSharp.exe” “D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\ConsoleDemoPostSharp.psproj” “D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\Before-PostSharp\ConsoleDemoPostSharp.exe” “/P:Output=obj\Release\ConsoleDemoPostSharp.exe ” “/P:ReferenceDirectory=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp ” “/P:Configuration=Release ” “/P:Platform=AnyCPU ” “/P:SearchPath=bin\Release\,obj\Release\, ” “/P:IntermediateDirectory=obj\Release\PostSharp ” “/P:CleanIntermediate=False ” “/P:MSBuildProjectFullPath=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\ConsoleDemoPostSharp.csproj ” “/P:SignAssembly=False ” “/P:PrivateKeyLocation= ”

PostSharp 1.0 [1.0.12.469] – Copyright (c) Gael Fraiteur, 2005-2008.

EXEC : warning PS0064: A new version of PostSharp 1.0 is available. You have currently 1.0.12.469 and you could download the version 1.0.13.630 from http://www.sharpcrafters.com/postsharp/download.

info PS0035: C:\Windows\Microsoft.NET\Framework\v2.0.50727\ilasm.exe “D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\PostSharp\ConsoleDemoPostSharp.il” /QUIET /EXE /PDB “/RESOURCE=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\PostSharp\ConsoleDemoPostSharp.res” “/OUTPUT=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\ConsoleDemoPostSharp.exe” /SUBSYSTEM=3 /FLAGS=1 /BASE=19595264 /STACK=1048576 /ALIGNMENT=512 /MDV=v2.0.50727

ConsoleDemoPostSharp -> D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\bin\Release\ConsoleDemoPostSharp.exe

Done building project “ConsoleDemoPostSharp.csproj”.

We then run the program and enjoy the power of PostSharp :

2010-04-17 23:29:12,705 [1] ERROR 2010-04-17 23:28:43,265 [1] ERROR D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\Program.cs ConsoleDemoPostSharp.Program [(null)] – postsharp :entering Void FirstFunction(Int64) “634071437232634478

[more data]

So , as you see it gives you not only the trace , but also the value : 634071437232634478

You can download code from http://msprogrammer.serviciipeweb.ro/wp-content/uploads/loggingDemo.zip

Additional resources

Tracing : http://www.15seconds.com/Issue/020910.htm

Enterprise logging : http://msdn.microsoft.com/en-us/library/cc309257%28v=MSDN.10%29.aspx

VS2010 with Dotfuscator : http://msdn.microsoft.com/en-us/library/ff460257.aspx

CCI metadata : http://ccisamples.codeplex.com

Postsharp 2.0 improvements over 1.0 : one of many examples here : http://www.sharpcrafters.com/blog/post/introducing-postsharp-2-0-1-notifypropertychanged.aspx

Saving Setting for Windows Forms

Saving and retrieving application settings

Every application that I have made needs at minimum two things, that we will put on the generic term “ settings “:

1. “remember” their state – information that are read at the beginning, write at the end of the program . We will name those “local settings” because there are different by each user that uses the application.

2. Connect with other applications (databases, web services, other programs ) and remember the “connection” settings – information that is read and does not change often ( number of writes is minimized). We will name this “global settings”.Most of the time the writing is realized by setup and/or a new application dedicated to application administration.

Usually the settings are saved in a file persisted on local hard disk. From the programmer perspective, there are four questions that arise:

1. when to save

2. where to save

3. how to save

4. how to make the information confidential.

When to save

The saving can be done in two separate moments: on installing the application and in running the application. Usually, the global settings(information that does not change often such as database connection) is persisted on application setup and read when the application starts. The local settings information (such as last action of the user) is read when the application starts and it is write at the application end.

Where to save

For a desktop application there are two places to save the data for a application : the folder where the applications is installed by the user (usually %programfiles% , can be obtained in .NET with Path.GetDirectoryName( Assembly.GetEntryAssembly().GetName().CodeBase)) and the local folder for application data for this user (%USERPROFILE%\AppData\Local – obtained in .NET with
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
). The first one is for global settings, the other one for local user settings.

How to save

We will enumerate here several methods, remaining for you the task to choose between the best. We will deliberately skip the method in which you use a file and you wrote information there in a proprietary format.
In the next examples we will save/retrieve two named properties : DatabaseConnection and LastAction
Save method 1 : from Settings within Visual Studio
You can create settings for your project very easy. Load your project in Visual Studio, click on toolbar Project=>Properties, select the tab “Settings” and create the settings. In the picture you will see two settings, one with user scope and one with application scope:
clip_image002
By default Visual Studio creates a class named “Settings” and puts code for retrieving/storing the settings that you create. More – the application settings does not have a “set” by default – it is normal since it is stored in application config file – an ordinary user cannot write this setting.
The code for retrieving/saving the settings is the following:
Console.WriteLine(Properties.Settings.Default.DatabaseConnection);
Console.WriteLine(Properties.Settings.Default.LastAction);
Properties.Settings.Default.LastAction = “difference”;
Properties.Settings.Default.Save();
//you can reset the values by
//Properties.Settings.Default.Reset();
For more details please refer to the following links :

· Application Settings Architecture , http://msdn.microsoft.com/en-us/library/8eyb2ct1.aspx

· Application Settings Overview , http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx

Video tutorial : http://www.youtube.com/watch?v=-JDoZU0HBBo&feature=PlayList&p=70009BDDADB00AEF&index=1

Save method 2 : from application configuration file

You can read/save directly from application configuration file. Add an application configuration file to the project and a reference to System.Configuration . In the app.config file add
<appSettings>
<add key=”DatabaseConnection” value=”name=Stargate”/>
<add key=”LastAction” value=”add”/>
</appSettings>
And the code is the following:
var app=ConfigurationManager.AppSettings;
foreach (var key in app.AllKeys)
{
Console.WriteLine(string.Format(“{0}={1}”,key,app[key]));
}
Observation 1 : Please ensure you put in the app.config file file just global settings. Otherwise the application must have administrative rights to modify the app.config file.
Observation 2 : For asp.net applications , the modifying of Web.config will result in restarting the application – that is NOT a good behaviour.

Video Tutorial : http://www.youtube.com/watch?v=Axkt_KE0JX4&feature=PlayList&p=70009BDDADB00AEF&index=2


Save method 3 , create a new configuration :

This method is a combinations between method 2 and 3 : we have an intermediate class to save and we save in the config file . It is somewhat more to write about, but it is more safe – and can be modified and/or tested easily.
First we create the class :
public class MyConfig : ConfigurationSection
{
[ConfigurationProperty(“DatabaseConnection”)]
public string DatabaseConnection
{
get
{
return base[“DatabaseConnection”].ToString();
}
set
{
base[“DatabaseConnection”] = value;
}
}
[ConfigurationProperty(“LastAction”)]
public string LastAction
{
get
{
return base[“LastAction”].ToString();
}
set
{
base[“LastAction”] = value;
}
}
}
Next , we put in the application configuration file the settings :
<configSections>
<sectionGroup name=”MyApplicationSettings”>
<section name=”MyConfig” type=”AppSettingsConsole.MyConfig, AppSettingsConsole” restartOnExternalChanges=”false” allowDefinition=”Everywhere” />
</sectionGroup>
</configSections>
<MyApplicationSettings>
<MyConfig DatabaseConnection=”name=Stargate” LastAction=”add”>
</MyConfig>
</MyApplicationSettings>
And third we wrote code to retrieve :
MyConfig m = (MyConfig)System.Configuration.ConfigurationManager.GetSection(“MyApplicationSettings/MyConfig”);
Console.WriteLine(m.DatabaseConnection);
Console.WriteLine(m.LastAction);

Video Tutorial : http://www.youtube.com/watch?v=oglDeV7sc94&feature=PlayList&p=70009BDDADB00AEF&index=3

Save method 4, XML file :
This is the method with the more liberty. We can define any class we want to preserve properties – we just need to serialize the class.
public class MySettings
{
static XmlSerializer xs;
static MySettings()
{
xs = new XmlSerializer(typeof(MySettings));
}
public string DatabaseConnection { get; set; }
public string LastAction { get; set; }
public void SaveToFile(string NameFile)
{
using (StreamWriter sw = new StreamWriter(NameFile))
{
xs.Serialize(sw, this);
}
}
public static MySettings RetrieveFromFile(string NameFile)
{
using (StreamReader sw = new StreamReader(NameFile))
{
return xs.Deserialize(sw) as MySettings;
}
}
}
And the code to save is easier :
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string FileName = Path.Combine(folderPath, “mysettings.txt”);
MySettings ms = new MySettings();
ms.DatabaseConnection = “name=Stargate”;
ms.LastAction = “add”;
ms.SaveToFile(FileName);
MySettings msRetrieve = MySettings.RetrieveFromFile(FileName);
Console.WriteLine(ms.LastAction + ” — ” + ms.DatabaseConnection);
Video Tutorial : http://www.youtube.com/watch?v=MtK3zZYjfS0&feature=PlayList&p=70009BDDADB00AEF&index=0
Save method 5, Ini Files

http://jachman.wordpress.com/2006/09/11/how-to-access-ini-files-in-c-net/
http://www.codeproject.com/KB/cross-platform/INIFile.aspx
Save method 6, Database
It’s obvious that you can have a table with 3 columns :Object, Name and Value. Access this column with EF, L2S , NHibernate or any other framework
Save method 7, Registry

Just the code
using (RegistryKey r = Registry.CurrentUser.CreateSubKey(@”Software\App”))
{
{
r.SetValue(“myvalue”, “1”, RegistryValueKind.String);
}
}
using (RegistryKey r = Registry.CurrentUser.CreateSubKey(@”Software\App”))
{
Console.WriteLine(r.GetValue(“myvalue”));
}
Video Tutorial : http://www.youtube.com/watch?v=UeBPTbWgthM&feature=PlayList&p=70009BDDADB00AEF&index=4

Summary

In this chapter we have shown different ways to store application settings in various file formats. A final recommendation is to store application global data in config file (either web.config, either app.config) and local user in XML file ( in
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
folder). More, for each desktop application please provide a way to edit the config file – and make sure you request elevated privileges.