Thursday, March 23, 2017

C# Things I've Been Learning Lately

How to convert a specific type into a generic type
(From the C# error message "cannot convert type xyz  to 'T')
The magic is in "Task.FromResult((T) Convert.ChangeType(result, typeof(T)));"
This is not considered good practice, but this is a  contrived example of implementing a mock for a GetAsync() method.

        

       public async Task GetAsync(string url)
        {
            return await Task.Run(() => GetAnimal(url));
        } 

       private Task GetAnimal(string url)
        {
            string result = null;
            if (url.Contains("mammal"))
            {
                result = "Giraffe";
            }
            ....
            return Task.FromResult((T) Convert.ChangeType(result, typeof(T)));
        }





How to use Console.WriteLine() in MVC .Net Applications for Debugging.

The easiest way is to use "Debug" statements like this:

Debug.WriteLine($"animal = {animal}");

Make sure in your project's Properties that Build/"Define DEBUG constant" is checked.
Then your debug statements will appear in the "Output" window.



How to selectively return values from Moq.  Recently I needed to return different values from long strings of input to Moq.  I was delighted to know the It.Is will take a lambda expression returning true or false.


var vetMoq = new Mock<IVeterinarian>();
/*
string url1 = "asdflksdflfklklsjss Tiger asdfasdfasdfas";
string url2 ="asdflksdflfklklsjss Horse asdfasdfasdfas";
*/
vetMoq.Setup(animal => animal.Diet(It.Is<string>(url => url.Contains("Tiger")).Returns("carnivore");
vetMoq.Setup(animal => animal.Diet(It.Is<string>(url => url.Contains("Horse")).Returns("herbivore");




How to iterate over Enum types:
foreach (var myType in 
   Enum.GetValues(typeof(MyType)).Cast<MyType>())
{
...
}

How to create a case-insensitive dictionary with a "string" key and a "MyType" value.
private static readonly Dictionary< string, MyType> _dictionary = 
  new Dictionary<string, MyType>(StringComparer.InvariantCultureIgnoreCase);
The Dictionary class takes an optional parameter of IEqualityComparer<tkey>. By passing in "StringComparer.InvariantCultureIgnoreCase" you create a dictionary that is case-insensitive for the string keys.

How to capitalize the first letter of each word in a string? String functions "ToUpper()" and "ToLower()" have a cousin, "ToTitleCase()" that capitalizes the first letter in each word
System.Globalization.TextInfo textInfo = 
        new System.Globalization.CultureInfo("en-US", false).TextInfo;
title = textInfo.ToTitleCase("we hold tHese tRuths tO be Self evident"); 
//We Hold These Truths To Be Self Evident

How to read data from an embedded file? First add the file to your project and set its Property "Build Action" to "Embedded Resource".
var assembly = Assembly.GetExecutingAssembly();
var name = assembly.GetName().Name;
var resourceName = $"{name}.MyTextFile.txt";

using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
    using (StreamReader reader = new StreamReader(stream))
    {
        while (!reader.EndOfStream)
        {
            string line = reader.ReadLine();
     ...
        }
    }
}

Tuesday, March 21, 2017

Performance Profiler in Visual Studio Not Showing Function Names

In Visual Studio 2015 while doing performance profiling, I ran into the problem of memory addresses of functions being shown instead of their names.

During operations I got these errors:

VSP2340: Environment variables were not properly set during profiling run and managed symbols may not resolve.  Please use vsperfclrenv before profiling.

and

Error        DA0002: It appears that the file was collected without properly setting the environment variables with VSPerfCLREnv.cmd. Symbols for managed binaries may not resolve.        C:\Git\gm.marketing.marketplace\MarketPlace.Web\Report170320(2).vsp    0   

Both of these issues should not happen if you are using the profiler inside Visual Studio.

The root cause was not running Visual Studio in Admin mode from the start.
Here's an example scenario to get functions names in Visual Studio 2015.

Start Visual Studio in Admin mode:


 Select from the tool bar "Analyze" > "Performance Profiler..." and then "Start"



 Select the appropriate method.  I've been using "Instrumentation" lately.



 Select your projects and then "Next"



Check "Enable Tier Interaction Profiling"

Then, "Next", and finally, "Finish"

IE should launch, and run through your test scenario.
 Then select "Stop profiling".



The Summary report will appear:

Then, if you select the "Functions" report, your functions should appear with a friendly name.