Twitter Weekly Updates for 2010-05-02
- mvc contest : http://www.mvcmelee.com/faq.html #
- programmer bill of rights :http://www.codinghorror.com/blog/2006/08/the-programmers-bill-of-rights.html #
Powered by Twitter Tools
Powered by Twitter Tools
Errors interception and rising
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).
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
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
intercept global errors in WinForms, ASP.NET , WPF, Silverlight application
ELMAH – intercept ASP.NET errors , http://code.google.com/p/elmah/
Logging : http://msprogrammer.serviciipeweb.ro/2010/04/19/logging-and-instrumentation/
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 😉 )
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
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” .
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.
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} => {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
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
Powered by Twitter Tools
This is the ultimate reference of reading web pages.
IF you want to do it yourself , you can try with WebRequest , http://msdn.microsoft.com/en-us/library/system.net.webrequest.aspx . But not all HTML is an XML – so you must find a method to parse. But am I the only one ?No – so I found the HTML Agility Pack , http://www.codeplex.com/htmlagilitypack , that knows how to transform HTML in XML. The code is easy :
HtmlWeb hw = new HtmlWeb();
hw.AutoDetectEncoding = true;
HtmlDocument doc = hw.Load(Url);
HtmlNode NodeRoot = doc.DocumentNode;
And from NodeRoot you can start XPATH with SelectNodes . Try it – it is awesome!
Powered by Twitter Tools
The two addons that I can not live without in Sql Server and that, more , are free :
The SSMS Tools Pack maintains a history of your commands . More, it saves on the C:\SSMSTools\SQLQueryActionLog
The Sql Search finds a text in the objects in the database – very useful if you decide to change a column name and find all stored procedures that have this reference
Powered by Twitter Tools
It’s the second year that I am MVP for C# for Romania – and I feel good about it!
Thursday, April 01, 2010
Re: Andrei Ignat, Most Valuable Professional, Visual C#
To whom it may concern,
It is with great pride we announce that Andrei Ignat has been awarded as a Microsoft® Most Valuable Professional
(MVP) for 4/1/2010 – 4/1/2011. The Microsoft MVP Award is an annual award that recognizes exceptional
technology community leaders worldwide who actively share their high quality, real world expertise with users and
Microsoft. All of us at Microsoft recognize and appreciate Andrei’s extraordinary contributions and want to take this
opportunity to share our appreciation with you.
With fewer than 5,000 awardees worldwide, Microsoft MVPs represent a highly select group of experts. MVPs
share a deep commitment to community and a willingness to help others. They represent the diversity of today’s
technical communities. MVPs are present in over 90 countries, spanning more than 30 languages, and over 90
Microsoft technologies. MVPs share a passion for technology, a willingness to help others, and a commitment to
community. These are the qualities that make MVPs exceptional community leaders. MVPs’ efforts enhance
people’s lives and contribute to our industry’s success in many ways. By sharing their knowledge and experiences,
and providing objective feedback, they help people solve problems and discover new capabilities every day. MVPs
are technology’s best and brightest, and we are honored to welcome Andrei as one of them.
To recognize the contributions they make, MVPs from around the world have the opportunity to meet Microsoft
executives, network with peers, and position themselves as technical community leaders. This is accomplished
through speaking engagements, one on one customer event participation and technical content development.
MVPs also receive early access to technology through a variety of programs offered by Microsoft, which keeps
them on the cutting edge of the software and hardware industry.
As a recipient of this year’s Microsoft MVP award, Andrei joins an exceptional group of individuals from around the
world who have demonstrated a willingness to reach out, share their technical expertise with others and help
individuals maximize their use of technology.
Sincerely,
Rich Kaplan
Corporate Vice President
Customer and Partner Advocacy
Microsoft Corporation
Since I am active on asp.net/mvc I find many peoples asking about
For answering, I have made a small application with MVC2 in order to detail my answer.
First the problem :
You have Employees and Department.Each Employee belongs to an Department (let’s forget the fact that the employee can belong for a final date to the Department or any other life ideas)
The request is to create and view Employees .(forget delete,update – if I will have time and/or by general request , I will do this also this)
The database:
The beginning of the application :
First Layer , Data Access Layer
I use EF 3.5 (not 4.0 with POCO style – because is not ready yet) and make an edmx file and let EF put his classes.
You can use also ADO.NET with StoredProc, L2S, NHibernate or any other ORM you want.
Second Layer,Business Logic :
This is the layer where the logic should intervene (e.g., the name should be not null ).
Here is the list for Employee :
namespace BusinessLogic { /// <summary> /// TODO : add IDataErroInfo in order to validate /// TODO : add the department /// </summary> public class Employee { public long ID; public string Name { get; set; } public Department Department{ get; set; } public void SaveNew() { //TODO : validate before save //TODO : automapper using (DAL_EF.testsEntities te = new DAL_EF.testsEntities("name=myconnection")) { DAL_EF.Employee e = new DAL_EF.Employee(); e.Name = this.Name; //TODO : what if dept. deleted ? e.Department =te.Department.Where(d=>d.ID== this.Department.ID).FirstOrDefault(); te.AddToEmployee(e); te.SaveChanges(); } } } public class EmployeeList : List<Employee > { public void Load() { using (DAL_EF.testsEntities te = new DAL_EF.testsEntities("name=myconnection")) { foreach (var emp in te.Employee.Include("Department")) { //TODO : use automapper Employee e=new Employee() { ID = emp.ID, Name = emp.Name }; e.Department=new Department(){ ID=emp.Department.ID,Name=emp.Department.Name}; this.Add(e); } } } } }
Please pay attention for Load procedure in EmployeeList : it uses the first layer, DAL, but it can use any ORM framework.
Third layer, ViewModel:
Because all the views for employees will need a select list for department ( either for sorting, creating or updating) I have put a base ViewModel class that retrieves the list of Departments:
namespace MVCAppEmp.Classes { public class ViewModelEmployee { public static SelectList ListOfDepartments { get { //TODO : put this into cache to not load every time DepartmentList dl = new DepartmentList(); dl.Load(); return dl.SelectFromList(x => x.ID.ToString(), y => y.Name); } } } public class ViewModelEmployeeCreate : ViewModelEmployee { public Employee emp=new Employee(); } public class ViewModelEmployeeList : ViewModelEmployee { public EmployeeList employees; public void Load() { employees = new EmployeeList(); employees.Load(); } } }
Fourth Layer , MVC itself – view and controller :
<% =Html.ValidationSummary() %> <% using (Html.BeginForm()) { %> <h2>Create</h2> List of departments : <% =Html.DropDownList("DepartmentID", MVCAppEmp.Classes.ViewModelEmployee.ListOfDepartments)%> <%=Html.EditorFor(model => model.emp)%> <input type="submit" value="create" /> <%} %>
and the controller
// POST: /Employee/Create // TODO: make a binding for employees [HttpPost] public ActionResult Create(Employee emp,long DepartmentID) { try { emp.Department = new Department() { ID = DepartmentID }; emp.SaveNew(); return RedirectToAction("Index"); } catch(Exception ex) { ModelState.AddModelError("", ex.Message); return View(new ViewModelEmployeeCreate(){emp=emp}); } }
So to answer the questions :
You will find attached the application and the sql to create the database :
For MVC2 /MVC 3
http://msprogrammer.serviciipeweb.ro/wp-content/uploads/ASP.NETMVCORMandViewModels_135E/emp.zip
For MVC 4
http://msprogrammer.serviciipeweb.ro/wp-content/uploads/ASP.NETMVCORMandViewModels_135E/empMVC4.zip
What to do next, in order to familiarize yourself :
1. Make the update of the employees .Create view, save.
2. Filter the list of the employees on department. Search for all employees beginning with A that belong to IT department.
3. Search for TODO’s : there are part of other tutorials – but it will help you in MVC (and other!) development
This post have a continuation here:
http://msprogrammer.serviciipeweb.ro/2010/07/05/asp-net-mvc-and-dos-re-using-the-viewmodels/