Category: .NET

Maintaining history of data

 

What is this about?

I tend to quote Fowler: “Usually when we see properties on a class, they represent questions we can ask of an object now. However there are times when we don’t want to just ask questions about a property of an object now, we also want to ask these questions about some point in the past when things may have changed. “

For example , we want to track every change that occurs at an Employee ( changing name, salary) and see the previous versions( what was the salary 2 years ago ?)

So what are the software solutions to do an audit log ? First, we should have a history table for each table that we want to maintain an audit log. E.g. Employee => EmployeeHstory

Solution 1 : Coding / Event Sourcing

That means code should maintain history himself – i.e. adding to the history table every modifications.

For Entity Framework this can be done easy, by overiding SaveChanges.

Demo at https://youtu.be/YZ9GDjFApns 

Solution 2 : Table Triggers

This can be done from database . There are triggers for insert , update, delete – and those triggers insert the data in the history table

Demo at https://youtu.be/9xsvCJ-1f7Q

Solution 3, Temporal Tables, Microsot  Sql Server 2016 :

Documentation at https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables 

Limitations at https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-table-considerations-and-limitations 

Demo at https://youtu.be/1Q3DmXJI5h8

Five common mistakes for ASP.NET MVC accesing resources : css, js, images, ajax

This is a Razor /MVC5 variant of older post
http://msprogrammer.serviciipeweb.ro/2010/10/09/five-common-mistakes-for-asp-net-mvc-accesing-resources-css-js-images-ajax/

To have once for all the link to show to people, because too much makes the same error again and again. (From here – you can use ResolveUrl or Url.Content – it’s the same for me. I use ResolveUrl because I used first …)

Case 1 The image does not display

Please check you have the following :

 <img src="@Url.Content("~/Content/images/YOURIMAGE.jpg" )" alt="image" style="border:0" /> or 
 
<img src="~/Content/images/YOURIMAGE.jpg" alt="image" style="border:0" /> 

Case 2 The css does not show

Please check you have the following :

 @string.Format("<link href="{0}" type="text/css" rel="stylesheet" />", Url.Content("~/Content/your.css"))  

or

 <style type="text/css">
@import '@Url.Content("~/Content/your.css")';

</style>  
  <style type="text/css">
<link href='~/Content/your.css' type='text/css' rel='stylesheet' />

</style>  

Case 3 The js does not execute (undefined error)

3.1 Please check you have the following :

 <script type="text/javascript" src="@Url.Content("~/Scripts/yourjs.js")"></script> 

or

 <script type="text/javascript" src="~/Scripts/yourjs.js"></script> 

This should be either in _Layout.cshtml, or in the scripts section

 @section scripts {   } 

in your .cshtml file.
3.2 please check in browser console ( press F12 ) for any javascript error that code may have

Case 4 The js does execute in .cshtml page, but did not execute under js file

Please check you DO NOT have the following @something in the js file. The js file is not interpreted by the same engine as cshtml, so can not interpret asp.net tags. Instead , add a parameter to your function for each @ variable that you have. Simple example : Let’s say in cshtml you have :

 <script type=”text/javascript”>

function Generate(){

window.open('@Url.Action(“About”)’);
}

</script> 

and you call Generate() from .cshtml file. Now you want the same in a .js file. The function Generate will have a parameter instead of Razor variable

 function Generate(url){  window.open(url); } 

and call like this from .cshtml file:

 Generate('@Url.Action("About")'); 

Case 5 The ajax request gives you a 404 error.

Please ensure that you have

 @Url.Content("~/path”) 

and not

 /path 

when you call the Ajax URL

Bonus 1: T4MVC , http://mvccontrib.codeplex.com/releases

Bonus 2: Edit the project file and put <MvcBuildViews>true</MvcBuildViews>

( short url: http://bit.ly/asp5Mistakes)

Async + sync completion + lock

Let’s suppose that you have 2 functions = one true sync and one true async . Let’s suppose more that the sync one can must finish before calling next time ( think about some weird COM component or , in our days, SqlConnection )

If we look just at the async function , we could wait for all. However, the sync function must be called sync

One solution is to make different calls:


var list = new List<Task<int>>(nr);
//add async to list

await Task.WhenAll(list)

//call each sync



But I want to make really async – and one solution is lock

We could wrote the sync function in async manner like this:


//SemaphoreSlim sem = new SemaphoreSlim(1);
static object myObject = new object();
async Task<int> syncTask(int i)         {             
lock (myObject)             
//try{                 
//await sem.WaitAsync();                                 
CallSyncFunction();                             
//}             
//finally             
//{                 
//sem.Release();             
//}                                   
}

The trick that I  used is lock, because the syntax is easier than SemaphoreSlim (BTW: if you want to learn about threading, jump directly to http://www.albahari.com/threading/)
In this manner, the sync function is modified in async -and, more, it waits for completion before entering the second time.

The code is on github on

More details in the Wiki https://github.com/ignatandrei/AsyncSyncLock/wiki or in the code https://github.com/ignatandrei/AsyncSyncLock/

spot errors in VB

Please spot the errors in the following code in VB.NET:

Dim Diff As String = con.ExecuteCommand(“SELECT DATEDIFF(Day, (select [date] from table where Username = ‘” + txtUserName.Text + “‘), ‘” & DateTime.Now.ToString() & “‘)”)
If (Diff > 30) Then
Response.Redirect(“PleaseChangeMyPassword.aspx”)
End If

 

( find at least 3…)

Side note:

No wonder Visual Basic has died ( more or less). Guess future of server javascript ….

Generating Visual Studio solution( or project) references

A Visual Studio pacakge is a plugin of Visual Studio that can do (almost) anything inside Visual Studio

I have made a small project that generates a list of all solution ( or project) references from VS:

 

            foreach (var project in dte.Solution.Projects)
            {
                var p = project as Project;
                if (p == null)
                {
                    continue;
                }

                var vsproject = p.Object as VSLangProj.VSProject;
                if (vsproject == null)
                    continue;

                string nameProject = p.Name;
                foreach (var reference in vsproject.References)
                {
                    var r = reference as Reference;
                    if (r == null)
                        continue;

                    var pathRef = r.Path;

                    //this is a package                    
                    var pa = new PackageAdd();
                  
                    pa.ProjectName = p.Name;
                    pa.IdentifierPackage = r.Identity;
                    pa.VersionPackage = r.Version;
                    pa.NamePackage = r.Name;

                  



                    if (r.SourceProject != null)
                    {
                        
                        pa.NamePackage = r.SourceProject.Name;
                    }
                    sb.AppendLine(pa.ToString());
                }
            }

You can find the solution at https://github.com/ignatandrei/ToolsAndUtilities/tree/master/VS2015/FindReferencesVS

Also the video is at https://youtu.be/a3YHVjJ9fm4

Enjoy!

Thank you for all the API

In our days it is simpler to make an application by putting together some API . I wanted to make a list of all my 5 Minutes .NET playlist videos . First, I have tried to find an application(nothing). Then I have read  You Tube API from https://console.developers.google.com/apis/library . With 2 http requests( one for retrieving all videos from a playlist, the other to find video details) and a NuGet package to export to Excel/Word/PDF/HTML it was simple. You can find the whole project at https://github.com/ignatandrei/YouTube . A video demo at https://www.youtube.com/watch?v=wNHDsHtLBq4 . And the whole list at https://github.com/ignatandrei/ToolsAndUtilities/tree/gh-pages

IDisposable and Marshal.ReleaseCOMObject and dynamic in C#

 

If you have worked with COM, you know that for every COM object that you access is not only necessary to null the reference, but also call Marshall.ReleaseCOMObject .

This is a very error prone task, because you have all try / finally blocks

 
// declare a, ws, w 
try{ 
a=new Application(); 
ws = a.Workbooks; 
w = ws.Add(); 
//code 
}
 catch(...) {
 if( w != null){ 
Marshal.ReleaseComObject(w); 
w = null; 
}
 if(ws !=null){ 
Marshal.ReleaseComObject(ws); 
ws = null; 
} 
if( a!= null) { 
Marshal.ReleaseComObject(a); a= null; 
} 
} 

All of this could be done easy with IDisposable, if

1. IDisposable calls the Marshal.ReleaseCOMObject

2. Find a way to call methods / properties on the COM object from the class that implements IDisposable

 

I have done this and the result is like this:

 
using (dynamic a = new ComDisposable(new Application())) { 
using (dynamic ws = a.Workbooks) { 
using (dynamic w = ws.Add()) { 
using (var shs = w.Sheets) { 
using (var s = shs[1]) { 
//Worksheet a; 
using (var r = a.Range("A1")) { 
r.Value2 = "http://ignatandrei.github.io/ToolsAndUtilities/";; 
using (var f = r.Font) { 
f.Bold = true; 
}
 }
 }
 }
 w.SaveAs(fileName); 
w.Close(); 
} 
}
 a.Quit(); } 

 

Video at https://youtu.be/2qbAcSjL1gU

NuGet package at https://www.nuget.org/packages/ReleaseComObjectDisposable/

AppContext

AppContext is like Application in ASP.NET (MVC). You can see the value all over the application

AppContext.SetSwitch("OCR", true);

And we can have the result in all dll’s by

 public bool IsOCREnabled()
        {
            bool test;
            if (!AppContext.TryGetSwitch("OCR", out test))
                return false;

            return test;
        }

Video demo at https://youtu.be/GMgn4o3yPqw

Instrumentation in C# / .NET

For many programmers a try/catch with stack trace it is enough

try
{
var p = new Person();
p.DateOfBirth = DateTime.Now.AddYears(-10);
p.Drink(10, 2);
}
catch (Exception ex)
{
Console.WriteLine("ERROR OCCURED " + ex.StackTrace);
}

Others want to see also functions arguments, like in


p.Drink(10, 2);

will produce the result

ERROR An exception occured in method InstrumentationPostSharp.Person.Drink with (beersNumber = 10 , vodkaNumber = 2)

For this you can install the package
https://www.nuget.org/packages/LoggerAspect.Nlog

that have full source code at
https://github.com/vnvizitiu/AOP/tree/master/PostSharpTutorial

and watch my video for more details
https://youtu.be/qe2kpuuWXkw

RavenDB embedabble

I have made an application with RavenDB embeddable.

The good part is that is embeddable and easy to work with – at least, at start.

What I have learned:

  • If you forgot to use using, then RavenDB will throw an exception complaining about multiple sessions. Code:
 using (var session = instanceDefault.OpenSession(DatabaseName()))
{

//code
}

 

  • If you use multiple instance of the same EmbeddableDocumentStore , even on different default databases , then will complain about “temp path already used by another database instance “ . And the generics do NOT share the same instance of a static variable. And when you dispose a static singleton instance ? At the final of the application ( do not forget , otherwise you may have again “temp path already used by another database instance ” !)

 

  • The most simple index for new databases is RavenDocumentsByEntityName . Code:
//static EmbeddableDocumentStore instanceDefault;
var dbc = instanceDefault.DatabaseCommands.ForDatabase(DatabaseName());
                var defIndex = new RavenDocumentsByEntityName();
                
                defIndex.Execute(dbc,new DocumentConvention()
                {
                    DefaultUseOptimisticConcurrency = true                    
                    
                } );

 

  • If you create an index, create in the Database that needs. Otherwise if will complain when you get the data.  ( see previous code)

 

  • To manage data / databases , there is RavenDB Management Studio – a fancy name for an application that you can access ( by default ) at http://localhost:8080 . Code:
            instanceDefault = new EmbeddableDocumentStore();
//I have put this in app.config/web.config
            //instanceDefault.Configuration.Settings.Add("Raven/MaxSecondsForTaskToWaitForDatabaseToLoad", "60");
/*
<connectionStrings>
		<add name="RavenDB" connectionString="DataDir = ~\App_Data\Database"/>
	</connectionStrings>
   <appSettings>
	<add key="Raven/MaxSecondsForTaskToWaitForDatabaseToLoad" value="60"/>
*/
            instanceDefault.ConnectionStringName = "RavenDB";
            instanceDefault.Conventions.FindIdentityPropertyNameFromEntityName = (entity) => "ID";

            try
            {
                //To try in debug mode
                NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(8080);
                instanceDefault.UseEmbeddedHttpServer = true;
                instanceDefault.Initialize();

            }
            catch (ReflectionTypeLoadException ex)
            {
                string message = "LoaderExceptions:";
                ex.LoaderExceptions.ForEach(it => message += it.Message + ";");
                throw new Exception(message, ex);
            }


 

( do not let this into Web Application if you want to deploy to a third party host)

 

  • Copy / paste database do not work. You must backup and restore data( preferably with RavenDB Management Studio )

 

  • RavenDB documentation is ok – however, embeddable database is not so represented very well

 

If you want to see a sample ( not very good, though) repository, I have created one at https://github.com/ignatandrei/RomaniaOpenData/blob/master/ROP/ROPInfrastructure/Repository.cs

Bottom line: I think that is good enough.

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.