RSS

Tag Archives: .net

C# Dynamic-Typed Parameter Trap

A little tricky lesson today in C#.

Passing a dynamic-typed parameter to a method that has defined return type (ie: string, int, etc) will not return the defined type, instead the method will return dynamic type.

class Program
{
	static void Main(string[] args)
	{
		FooBarClass fooBar = new FooBarClass();

		var result1 = fooBar.Foo("Foo");

		dynamic bar = "Bar";
		var result2 = fooBar.Foo(bar);
	}
}

public class FooBarClass
{
	public string Foo(string fooArg)
	{
		return "This is Foo";
	}
}

In the above example, type of result1 is string, but type of result2 is dynamic, even though they both call same method that return string type.
result1
result2

This is because compiler do not evaluate dynamic type until runtime therefore it can’t determine return type at compile time.

This is important to point out because if we apply extension method to result2, it will throw exception at runtime, not compile time.

Example of extension method.

public static class FozBazClass
{
	public static void Foz(this string fozArg)
	{
		fozArg = "Test..." + fozArg;
	}
}
result1.Foz(); // this will execute normally
result2.Foz(); // this will throw exception

result2 exception

Just another reason we should avoid dynamic type.

Advertisements
 
Leave a comment

Posted by on May 29, 2018 in General

 

Tags: , , , ,

String as a Reference Type and Immutable

In .Net, string object is reference type, however when we pass the value like this

void Main()
{
    string s = "Test";

    TestString(s);
    Console.WriteLine("TestString: " + s); // Output is: TestString: Test
}

public static void TestString(string s)
{
    s = "TestString";
}

Why is the output “TestString: Test”, we know for sure string is a reference type and we assign new value to our parameter in TestString() method.

Turn out, beside being a reference type, string is also an immutable, which mean its value can’t be modified or changed. So when we assign new value to our parameter in TestString() method, it actually create new string object. It acts like value type but it isn’t a value type, it’s a reference type with immutable behavior.

 
Leave a comment

Posted by on May 15, 2018 in General

 

Tags: , , , ,

Float, Double, Decimal Types and DivideByZeroException

Most of us know the difference between Float, Double and Decimal types in .Net is the precision.

  • Float 32 bit (7 digits)
  • Double 64 bit (15-16 digits)
  • Decimal 128 bit (28-29 digits)

But most of us scratch our head over this:

var numerator = 10;
var denominator = 0;
var resultNoException1 = (float)numerator / (float)denominator; // Result Infinity, does not throw exception
var resultNoException2 = (double)numerator / (double)denominator; // Result Infinity, does not throw exception
var resultException = (decimal)numerator / (decimal)denominator; // Throw DivideByZeroException

Suffice to say throw/catch block won’t caught any exception on resultNoException1 and resultNoException2.

Why?

Because Float and Double types are binary floating point types (or sometimes being referred to as floating point types) while Decimal is decimal floating point types.

From MSDN:

Dividing a floating-point value by zero doesn’t throw an exception; it results in positive infinity, negative infinity, or not a number (NaN), according to the rules of IEEE 754 arithmetic.

 

 
Leave a comment

Posted by on May 2, 2018 in General

 

Tags: , , , , , , ,

What’s My .NET Framework Version?

Using Registry

Most accurate is through registry. For .NET Framework 1-4:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP

And newer .NET Framework:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full

The DWORD represents different .NET Framework version.

Using Code

Easier way is to use code:

void Main()
{
    GetVersionFromRegistry();
    GetNet45PlusFromRegistry();
}

private static void GetVersionFromRegistry()
{
    // Opens the registry key for the .NET Framework entry.
    using (RegistryKey ndpKey =
        RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
        OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
    {
        // As an alternative, if you know the computers you will query are running .NET Framework 4.5
        // or later, you can use:
        // using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
        // RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
        foreach (string versionKeyName in ndpKey.GetSubKeyNames())
        {
            if (versionKeyName.StartsWith("v"))
            {
                RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                string name = (string)versionKey.GetValue("Version", "");
                string sp = versionKey.GetValue("SP", "").ToString();
                string install = versionKey.GetValue("Install", "").ToString();
                //no install info, must be later.
                if (install == "")
                {
                    var version = versionKeyName + "  " + name;
                    Console.WriteLine(version);
                    version.Dump();
                }
                else
                {
                    if (sp != "" && install == "1")
                    {
                        var version = versionKeyName + "  " + name + "  SP" + sp;
                        Console.WriteLine(version);
                        version.Dump();
                    }
                }
                if (name != "")
                {
                    continue;
                }
                foreach (string subKeyName in versionKey.GetSubKeyNames())
                {
                    RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                    name = (string)subKey.GetValue("Version", "");
                    if (name != "")
                        sp = subKey.GetValue("SP", "").ToString();
                    install = subKey.GetValue("Install", "").ToString();
                    //no install info, must be later.
                    if (install == "")
                    {
                        var version = versionKeyName + "  " + name;
                        Console.WriteLine(version);
                        version.Dump();
                    }
                    else
                    {
                        if (sp != "" && install == "1")
                        {
                            var version = "  " + subKeyName + "  " + name + "  SP" + sp;
                            Console.WriteLine(version);
                            version.Dump();
                        }
                        else if (install == "1")
                        {
                            var version = "  " + subKeyName + "  " + name;
                            Console.WriteLine(version);
                            version.Dump();
                        }
                    }
                }
            }
        }
    }
}

private static void GetNet45PlusFromRegistry()
{
    const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
    string version = string.Empty;

    using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
    {
        if (ndpKey != null && ndpKey.GetValue("Release") != null)
        {
            version = ".NET Framework Version: " + CheckFor45PlusVersion((int)ndpKey.GetValue("Release"));
            Console.WriteLine(version);
            version.Dump();
        }
        else
        {
            version = ".NET Framework Version 4.5 or later is not detected.";
            Console.WriteLine(version);
            version.Dump();
        }
    }
}

// Checking the version using >= will enable forward compatibility.
private static string CheckFor45PlusVersion(int releaseKey)
{
    if (releaseKey >= 461308)
        return "4.7.1 or later";
    if (releaseKey >= 460798)
        return "4.7";
    if (releaseKey >= 394802)
        return "4.6.2";
    if (releaseKey >= 394254)
    {
        return "4.6.1";
    }
    if (releaseKey >= 393295)
    {
        return "4.6";
    }
    if ((releaseKey >= 379893))
    {
        return "4.5.2";
    }
    if ((releaseKey >= 378675))
    {
        return "4.5.1";
    }
    if ((releaseKey >= 378389))
    {
        return "4.5";
    }
    // This code should never execute. A non-null release key should mean
    // that 4.5 or later is installed.
    return "No 4.5 or later version detected";
}

Reference
Microsoft Docs

 
Leave a comment

Posted by on January 22, 2018 in General

 

Tags: ,

GAC and GACUTIL in a Nutshell

What’s GAC?

Global Assembly Cache.

What’s in the GAC?

See GAC content:

C:\> gacutil -l
or
C:\> gacutil /l
or a specific assembly:
C:\> gacutil -l msshrtmi

Or alternatively, look into the following folders:

.NET Framework 4 and newer: %windir%\Microsoft.NET\assembly.
Earlier versions of the .NET Framework: %windir%\assembly.

Accessing GACUTIL

If you have Visual Studio installed, GACUTIL should be accessible in Visual Studio Developer Command Prompt:

C:\Users\JohnDoe\Source> gacutil

Where’s GACUTIL?

If you don’t have Visual Studio, chances are GACUTIL is not recognized in the command prompt. But it doesn’t mean you don’t have it.

Try look in the following folders:

C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools

Or any other version available.

GACUTIL comes with Windows SDK. If you still can’t find, download Windows SDK.

Installing New GAC

C:\> gacutil /i MyLibrary.dll

GACUTIL will place the assembly in the GAC directory based on the version of .NET Framework used to compile the assembly.

You don’t need to restart your computer for the installation to take effect.

References

Global Assembly Cache GAC
GACUTIL
View GAC Content

 
1 Comment

Posted by on January 14, 2018 in References

 

Tags: , , ,

Unit Testing WIF’s ClaimsPrincipalPermission.CheckAccess

WIF 4.5 has ClaimsPrincipalPermission.CheckAccess method, very useful to check user’s authorization. You can use this as method call or attribute.

// Imperative method call
using System.IdentityModel.Services;
public ActionResult Index()
{
    ClaimsPrincipalPermission.CheckAccess("foo", "bar");

    return View();
}

// Attribute
[ClaimsPrincipalPermission(SecurityAction.Demand, Operation="foo", Resource="bar")]
public ActionResult ViewFoobar()
{
    return View();
}

Either way, how do we unit test this? My approach is to first abstract out ClaimsPrincipalPermission and create a new wrapper class that will be injected to the dependent class.

Abstract Out

using System.IdentityModel.Services;

public class ClaimsPrincipalWrapper : IClaimsPrincipalWrapper
{
    public void CheckAccess(string resource, string action)
    {
        ClaimsPrincipalPermission.CheckAccess(resource, action);
    }
}

Dependency Injection

using System.IdentityModel.Services;

public class HomeController : Controller
{
    private readonly IClaimsPrincipalWrapper _ClaimsPrincipalWrapper;

    public HomeController(IClaimsPrincipalWrapper claimsPrincipalWrapper)
    {
        _ClaimsPrincipalWrapper = claimsPrincipalWrapper;
    }

    public ActionResult Index()
    {
        _ClaimsPrincipalWrapper.CheckAccess("foo", "bar");

        return View();
    }
}

Unit Test

[TestMethod]
public void TestIndex()
{
    // Arrange
    var _claimsPrincipal = new Mock<IClaimsPrincipalWrapper>();
    _claimsPrincipal.Setup(m => m.CheckAccess(It.IsAny<string>, It.IsAny<string>));
    var _controller = new HomeController(_claimsPrincipalMock.Object);

    // Act
    var _result = _controller.Index() as ViewResult;

    // Assert
    Assert.IsTrue(_result.View != null);
}
 
Leave a comment

Posted by on May 4, 2015 in General

 

Tags: , , , , , , ,

Visual Studio 2012: Debugging Unit Tests Doesn’t Work

There’s a problem in Visual Studio 2012 where debugging unit tests doesn’t work. This often happens when you enable code coverage.

The solution is fairly simple, un-check any selected test setting file under Test > Test Settings.

This behavior is expected, at least according to Microsoft, they just don’t support debugging for code coverage.

 
Leave a comment

Posted by on May 1, 2015 in General

 

Tags: , ,

 
%d bloggers like this: