Page 2 of 6

WinMD Assembly

Windows 8 introduced WinRT(Windows Runtime) that allows us to develop applications based on C++, C#, Vb and JavaScript by allowing access to its Api and by allowing communication between different programming languages. Communication between languages is possible through Windows Runtime Component that creates WinMD Assembly. WinMD Assembly is a Assembly that contains metadata but can also contain types.

When you try to create Windows 8.1 store app you cannot add usual Class Library, you have to add Windows Runtime Component and there you can write your usual code.

Trying to add Class library to your Store App will result in “Unable to add a reference to project” error.

WinMD limitations (copied from https://www.microsoftpressstore.com/articles/article.aspx?p=2199428&seqNum=3):

  • The fields, parameters, and return values of all the public types and members in your component must be WinRT types.
  • Public structures may not have any members other than public fields, and those fields must be value types or strings.
  • Public classes must be sealed. If your programming model requires polymorphism, you can create a public interface and implement that interface on the classes that must be polymorphic. The only exceptions are XAML controls.
  • All public types must have a root namespace that matches the assembly name, and the assembly name must not begin with “Windows.”

Why would I need to create WinMD class library?

Lets explore it through Windows store app example.

Create new Solution and there add two Blank App.s for Windows 8.1 (one for C# and another for JS).

Both of these apps should have:

2x Textbox

1x Label

2x Button

Goal of this Application is to create Application where you can input data inside two different TextBoxes and combine their values inside Label after clicking button. Second goal is to copy some text value in your clipboard(simply copy some text with Ctrl+C) and display value in Label after clicking second button.

All this code can be easily achieved by writing it in backend of MainPage.xaml.cs file or inside JavaScript function, but we want our Application to share code, and that is here WinMD steps in. You can create methods that perform that actions and reuse it across different applications and different languages. Yup, even JavaScript can use WinMD classes written in C#.

Example of WinMD / Windows Runtime Component Assembly

MainPage.xaml

default.html

MainPage.xaml.cs – Buttons

Windows Runtime Component – Helper class

If you wish to inspect entire solution , download it from this link.

Please do not use code from solution  for your projects because no checks were implemented what so ever.

 

GAC (Global Assembly Cache)

You can locate GAC folder inside Windows directory. GAC folder contains only strongly named assemblies. All applications that are running on your machine can access GAC folder and use its assemblies. Benefits of storing strongly named assemblies inside GAC are:

  • There is no need to distribute that particular assembly with every new version of application
  • Assemblies stored in GAC folder are strongly named so you need not to worry about having two or more version of same assembly distributed.

How can i locate GAC folder?

There are actually two locations:

  1. Location for assemblies created with .Net Framework 2.0 to .Net Framework 3.5
  2. Location for assemblies created with .Net Framework 4.0 and newer

Usually you cal locate it by typing C:\Windows\assembly for older strongly named assemblies or C:\Windows\Microsoft.NET\assembly for newer strongly named assemblies.

If your machine is not installed on C drive or your windows folder is not named Windows simply type in File explorer : %WINDIR%\Assembly or %WINDIR%\Microsoft.NET\assembly and you there you can find GAC folder.

How to install Strongly named assembly inside Global Assembly Cache?

Add new Class library project to Solution and name it AssemblyToInstall and strong name it.

Drag and drop approach:

Just simple locate bin\Debug folder inside AssemblyToInstall project, locate AssemblyToInstall.dll file and drop it to appropriate location (C:\Windows\Microsoft.NET\assembly). Note that you can do this only if your user has elevated privileges.

Using GacUtil.exe

If you are using Visual Studio 2013 or 2015 version, you can search for Developer Command Prompt and run it as Administrator.

New console will open.

Navigate to project. Mine is located on D drive under charp folder

Next you will need to run gacutil toll with -i parameter (basically -i switch is telling gacutil that we want to install assembly) followed by Assembly dll we want to install.

run command: gacutil.exe -i AssemblyToInstall.dll

GAC

How to use gacutil to install strongly named assembly inside GAC folder

You should receive message: “Assembly successfully added to the cache”

If you receive message: “Failure adding assembly to the cache: Attempt to install an assembly without a strong name”. That means that you have not signed assembly.

Now navigate to %WINDIR%\Microsoft.NET\assembly\GAC_MSIL\AssemblyToInstall and there you can see your assembly and can use that path to provide reference to that assembly to all applications located on this machine.

Tomorrow we will continue with topic on how to implement side-by-side hosting.

Strongly named assemblies

Purpose of strong naming assemblies is to create unique identity for desired assembly. You would typically want to do that when you need multiple versions of same assembly to be used, when assembly must be installed inside GAC (global assembly cache) or when you want assemblies to be to be referenced by strongly named assemblies.

What does it mean to be strongly named?

Strongly named assemblies are assemblies that have:

Name (usually name of project)

AssemblyVersion (AssemblyVersion information)

Culture information (Assemblies are usually culture neutral but if you wish to change them you can access AssemblyInfo.cs file and change AssemblyCulture attribute)

Private/Public key token (main difference between strongly named assemblies and weakly named assemblies)

I wish to create strongly named assemblies! What do i do?

First you would create a project. That first step would create weakly named assembly. Next what you want to do is sign it. There are multiple ways to achieve this.

First Approach:

From Visual studio:

  1. Right click project
  2. Properties
  3. Select Signing tab
  4. Check “Sign the assembly” CheckBox
  5. From Drop-down control select New
  6. Input necessary Information
  7. Select Drop-down control again and find your  .pfx file

Strongly named assemblies

How to strongly name assemblies

Now when we know how to strong name assemblies we can continue to part on how to put an assembly in the global assembly cache.

 

 

Version assemblies

When talking about Version assemblies you would usually interact with AssemblyVersion, AssemblyFileVersion, AssemblyInformationalVersion Atrributes. Ability to successfully version assemblies is important while testing, debugging and deploying your assemblies. Why? Because it allows you and your team to inspect and debug same version of assemblies on one hand and to know what version of assemblies is are your customers using when talking about future requirements and current problems.

AssemblyVersion and AssemblyFileVersion

attributes

Can be manually located in your Solution explorer:

AssemblyInfo.cs

AssemblyInfo.cs file you can manually change values of a few Attributes. But now we will take look at AssemblyVersion and AssemblyFileVersion attributes. Both these Attributes provide default value in string format. Default values  should appear like this when you initially create project:

Number values inside string have specific meaning:

  1. value -> major value. Value should be changed when changes to your program are noticeable, like major User interface and under the hood changes
  2. value -> minor. increment this value when adding new capabilities to your Application.
  3. value -> build number. Obviously this value should be incremented when running a build
  4. value -> revision. Value that you should increment when choosing which build version to deploy

Build number and revision can be automated by using asterisk(*). Just change strings too look like this and their values will be incremented automatically after each build:

If you are developing small scale application it is best to change minor and major values manually.

AssemblyVersion attribute is used by other assemblies. When value of this attribute is changed, all assemblies that reference it must change value to match current value to ensure that communication between them will proceed uninterrupted.

AssemblyFileVersion attribute is used for deployment (when you ship assemblies to end user). You always need to know which version of assembly is shipped to your customer so that you can assist them, detect bugs and plan future changes.

AssemblyInformationalVersion

Usually you would not like to bore or even worse scare customers by displaying version of your Application in format like 8.56.7520.1459. You will want to display assembly version in user friendly format like 8.56 RC or 8 Orange, or any other format that will appeal to end user. This is where AssemblyInformationalVersion steps in. We can declare AssemblyInformationalVersion inside AssemblyInfo.cs file.

Nice. Please show me how to access these values.

First of. make sure that your AssemblyInfo.cs files has following values:

And inside main Method put following code:

This post has thought you how to version assemblies and was first post in Manage assemblies topic. Now we will continue to topic on how to strong name your assembly.

Streams

 Streams are sequence of bytes that you can use to read from or write to a backing store.

Let’s break down last sentence into a few parts:

  1. „Stream is a sequence of bytes“ – When working with data it is preferable that we read data in chunks of bytes. By breaking data in chunks we do not have to wait for our application to retrieve all parts of a data. For example, we may be accessing a audio file from network location and we want to process that audio file. Retrieving that file would take time and our application would need to wait until retrieval process is done before it can do some job. When using Streams we can specify how large chunks will be. You have seen this example: when listening to a music from popular music streaming site you will see information about bit-rate, that bit-rate represents chunk of data that is downloaded to you device for consumption.
  2. „that you can use to read from or write“ – Stream allows us to read, write or both to a storage device.
  3. „to a backing store“ – backing store represents your local Hard drive, memory, network location or any type of storage medium.

System class in System.IO namespace is a base class for all streams.

When using streams type of file (.txt, .mp3, .mkv, .doc, …) does not matter because it will be transformed to a sequence of bytes and your job is to convert that sequence to a meaningful representation of data. Retrieving data from a backing store will store data in a memory so you can use it in your application.

Every backing store type has appropriate streaming class for reading and writing operations. These streams are called Base Streams retrieve bytes. To consume:

  • FileSytem (local Hard drive, usbv drive…) you would use FileStream
  • Local memory -> MemoryStream
  • Remote location (Internet, Local network) -> NetworkStream

You use Stream Adapters allow you to transform bytes to types you would usually use in your application, such as integers and strings, by giving you access to classes and methods to consume data. Most commonly used are:

  • StreamReader/StreamWriter
  • BinaryReader/BinaryWriter
  • XmlReader/XmlWriter

For Streams to know where is beginning, current position, and end of a stream, pointer is used. Default position of pointer is at the beginning of a stream, or poistion 0. Streaming ends when pointer hits last position in a stream.

Example:

Lets say that we need to read 10 bytes which will be redistributed to positions 0-9, and we read data in chunks of 4 bytes. First we will read first 4 bytes and pointer will be at the position 3, then next four bytes are read and position will move to 7 and finally last two bytes will be read an pointer will be moved to position 9 and stream will end because end of stream is reached.

Caution! Sometimes, mostly while using network streams, when we expect stream to retrieve certain number of bytes we will not retrieve them all, so be careful when reading or writing data and always check if all bytes are written or read.

Is it possible to set pointer at certain position of a stream?

Yes it is, that process is called seeking. Note that MemoryStream andFile stream support it but NetworkStream does not. Also seeking allows us to read from beginning, end or custom location from within a stream.

Do I have to dispose of a Streams?

Yes, you should always dispose of a stream or or use using statement.

This conclude introduction to Streams lets see some examples.

Example of using FileStream:

 

 

Assembly class

Assembly class allows us to:

  • Load assemblies
  • Explore metadata and types
  • Create instance of types

Easiest way to load assembly is by load them using following methods :

GetAssembly (requires Type variable)

GetCallingAssembly (returns Assembly from which this method has been called)

These two methods have Assembly return type. After acquiring Assembly variable we can use it to get types that we want using GetType method.

Let’s explore Assembly class:

 

Events

Events allow us two things:

  1. If something important has occurred object notifies its subscribers about that occurrence.
  2. Objects that listen to another object are notified about changes of that object.

To declare event, you use event keyword followed by the type of delegate for the event, meaning we have to declare delegate before we can use event.

Typically, to raise an event, you would use protected void method. Name of that method by convention goes should be like this: OnEventName. Method should raise event  and provide two parameters object and EventArgs. Delegate upon whose type event uses should have two parameters: Object parameter is usually named sender and EventArgs parameter is named args. sender parameter is the source of the event. You should use EventArgs if you do not intend to send any parameters to subscriber, if on the other hand you wish to supply parameters create an class that inherits from from EventArgs and use that class as an parameter.

Example:

Lets create an application that is used to insert an employee to database. Upon inserting and after inserting few people should be notified, meaning we will have two events.

  • First, when we start inserting employee in database, we will notify our System Administrator that process of inserting has started. Also we will provide Sys Admin with DateTime value which will represent time when insert operation has started.
  • Second, after employee has been inserted in database, CEO, Website and System Admin will be notified.

You can also download entire solution for easier readability.

If you prefer using Action delegate instead of declaring delegates you can easily doe that. Just replace following code in HRDepartment class:

For now we will finish our journey with Delegates and return to Reflection.

 

Lambda expressions

A lambda expressions are an anonymous function that helps us write easy to read code.

Let’s see how we can achieve this. First we will take example from previous post about anonymous methods:

We can simplify this code by  removing delegate keyword and inserting => operator between anonymous method’s parameters and statement.

How do you pronounce => operator?

There are quite a few names for => operator. Here are a few typical names:

  • Goes to
  • Maps
  • Such that
  • Becomes

Lambda expressions do not look like a easier way to write delegates, can we for example remove delegate declaration?

You are correct. We can simplify thing even more with Action and Func.

Action

Action is a generic delegate type that describes a method that does not return a value. Action can have 16 overloads, of which not a single one describes a return type. You can picture action like a method with a void return type.

Action example

Code here is not deleted but commented out for you to see benefits of using Action. First of we do not need to declare delegate and lastly because we do not need to declare delegate we are free to decide upon our types while writing an Action.

Func

Func is a generic delegate type that describes a method that has an return a value. Func can have 17 overloads, but note that last type is your return type.

Func Example

Same as Action but note, that when looking at our sumOfTwoNumber Func, third int type is our return type.

We will now continue our journey with delegates by learning about events.

 

Anonymous methods

Anonymous methods allow us to create delegate methods inline.

What does that mean?

Let’s create a simple delegate whose role is to sum two numbers:

Would not it be nice if we could get rid of the SumTwoNumber method and just write it’s content while we instantiate delegate ? Yes it would and we can do it! Steps are:

  1. While instantiating your delegate, remove new… part.
  2. Write delegate keyword followed by input parameter in round brackets.
  3. Type your code inside curly brackets.

What we essentially did is we created a method without method name and thus we created anonymous method. Don’t believe me? Look again at the same code that has been reformatted a bit:

When you mentioned we can write delegate methods inline, does that mean we can write methods in one line only?

No, you can write as many lines as you want. Notice semicolon (;) on line 12, you can write additional code below. But beware of that feature, because if you write too many lines whole purpose of anonymous methods disappears and that is readability. Generally you would like to keep it to 1-3 lines, more than that would best be very good candidate for standalone method.

How do i know which parameters and return types to use wile writing an anonymous methods?

Your delegate tells you that information. In our example SumTwoNumberDelegate delegate expects return type int and two int input parameters, so that is what we provided him within anonymous method.

Anonymous methods are awesome! Are there any drawbacks to using them?

You would normally use delegate, instead of method, if you do not intend to use a function multiple times. On the other hand it makes no sense to write same anonymous method multiple times if you can reuse one method + it is easier to maintain that one method than multiple anonymous methods.

Can i make my code even simpler?

Yes you can, by using lambda expressions!

 

MethodInfo

Type’s class GetMethods method returns us with a array of MethodInfo objects. Similarly GetMethod method provided with a name of Method returns us a  MethodInfo object. It allows us to access a lot of information and interaction concerning specific Method, such as:

Check if a method is a constructor,

Access modifier of a method,

Method parameters,

Method name,

Invoking/Calling method

And many more…

Example:

We will continue our voyage with Reflection in next lesson about Assembly class.

 

© 2019 LearnC#WithDarko

Theme by Anders NorenUp ↑