Recently we were doing some work on ASP.NET Core Identity. We created a SQL Server database project to contain the database and imported the existing database. Unfortunately, we kept getting the following error on build.
The holy grail of application development is the ability to write an application once and target multiple platforms simultaneously. These types of applications are known as cross-platform applications. They span multiple platforms such as Windows, Mac, iOS and Android and multiple devices such as iPhone, iPad, Android Phones, Laptops, and PCs. At MILL5 we have extensive experience in building cross-platform applications using a variety of tools and frameworks such as Angular, Ionic, Framework7, PhoneGap, and Visual Studio for Mac.
One of our favorite tools for building cross-platform applications is Visual Studio for Mac (formerly Xamarin Studio). Visual Studio for Mac is the replacement of Xamarin Studio which was acquired by Microsoft after the purchase of Xamarin. Visual Studio for Mac gives us the ability to access the full capabilities of the underlying platform as well as running native code on the devices. This eliminates several complaints when building cross-platform applications such as access to platform capabilities (ex. cameras, location, video), native look-and-feel, and performance. This is especially important for applications that require direct access to platform capabilities such as camera, location, and video.
We will demonstrate building a cross-platform application using Visual Studio using sample application. We have chosen to build an advanced sample application, called “Hello Zoom”, that targets both desktop and mobile devices on multiple platforms. In this series of articles, we will create an application that targets Windows, Mac, iOS, and Android. From there we will look at what needs to be done to share common code, use native libraries on each platform, and build both cross-platform and native user interface components.
So what is “Hello Zoom”? Zoom is a video conferencing solution from Zoom. “Hello Zoom” is a sample application that integrates with the Zoom SDK to join a meeting (i.e. video conferencing). We chose this application because there are many interesting solutions that can be built based on video conferencing and it affords us the opportunity to discuss more advanced topics like native user interfaces and leveraging platform capabilities.
At the time of this article, Zoom does not support the .NET platform directly. What this means is that Zoom does not provide native .NET libraries. Instead, they provide libraries which are based on C++, Objective-C, and Java. These are platform specific languages. For example, C++ is for Windows, Objective-C for Mac OS X and iOS, and Java for Android. This represents an interesting challenge of “How do we talk to the Zoom library from .NET?”. This is a challenge that cross platform developers face often. If you are lucky, you will find a cross platform component that is published to a package repository like the NuGet gallery. Even then, you hope that the cross platform component is built in such a way that it is usable for your needs. In this case, we are not so lucky since there is no cross platform component available.
At this point you might ask “Why would you build an application that is cross platform? Why not go with native tools such as Xcode and Android Studio?”. There are so many reasons.
First, is time to market. If you have ever needed to build an application that targets multiple platforms, you are faced with building an application for each platform. That means you have to build and test every aspect of that application for each platform you target. That includes the business logic, user interface, and every other component needed to create the application. Cross platform applications simplify this effort by offering the ability to reuse code across each platform.
A question that often arises is “How much code can you reuse?”. For this sample application we will demonstrate reuse of business logic and user interface components. We would like to see 70% or more reuse before considering cross platform development. Using Visual Studio for Mac we expect to see much higher code reuse, 70 to 95 percent, in production scenarios.
Second, is consistency. The application we are about to build is a great example of this. When you look at the Zoom SDK, you will see that Zoom has taken liberties with their libraries on each platform. What that means is that there are differences such as naming, method signatures, and even features. By creating a cross platform component we are able to build the same application across many platforms with a consistent set of capabilities. This means a common set of features using the exact same API.
Third, is common user interface. This is a choice. There are many products and technologies that offer the ability to build common user interfaces. Each product and technology that offers the ability to create a cross platform user interface has their own advantages and disadvantages. Most take a least common denominator approach to building user interfaces. They often leverage technologies that are available on all platforms (ex. HTML) for building user interfaces, but lack the native capabilities of the underlying platform. Some offer great performance, others do not. Your choice of a cross-platform user interface technology should be based on the experience you want to create.
You must choose, but choose wisely. The true Grail will bring you life, the false Grail will take it from you. – Grail Knight
One of the big advantages regarding web-based applications is the plethora of choices for libraries and frameworks available to you as a developer. Having so many choices presents itself with additional challenges such as …
- “Which libraries and frameworks do you pick?
- “What is the adoption of each library or framework?”
- “Are these frameworks truly cross platform or do they just target a subset of devices?”
- “Can I find developers that know these libraries or frameworks?”
- “Are these libraries or frameworks supported by the developers that created them?”
These are just some of the questions you need the answers to when building web-based applications. This is why the plethora of libraries and frameworks available to web developers is also a big disadvantage. You must be disciplined when choosing the libraries and frameworks available to you so that you can limit yourself to those libraries and frameworks that give you the best adoption, longevity, and support for your application.
Another important requirement is the ability to access native capabilities on the device. In our case we are accessing a third-party library (i.e. Zoom) that needs access to native capabilities such as video, camera, networking, Bluetooth, and more. This is not possible with a web-based application unless you leverage more advanced products such as Adobe’s Cordova/PhoneGap or Appcelerator’s Titanium. These products allow you to build web-based applications that is hosted in a native shell application (i.e. container). This allows your web-based application to access native capabilities such as cameras, location, accelerometer, and contacts, through a plug-in architecture. In our situation there is no plug-in that is available to leverage the Zoom SDK from either PhoneGap or Titanium. We could try and create our own custom plug-in, but unfortunately that too is not possible. The Zoom SDK’s application programming interface has native user interfaces components for navigation, video, and settings. Using a web-based application makes integrating with these native user interface components extremely difficult, if not impossible.
Xamarin.Forms has none of these challenges. A user interface built using Xamarin.Forms is really just a set of views and controls that are mapped to platform-specific native user interface elements. For example, a Xamarin Forms Entry becomes a UITextView on iOS, an EditText on Android, and a TextBox on Windows. This is why a user interface using Xamarin.Forms is in fact a native user interfaces and when needed, you can also instantiation and interact with native user interface elements directly.
In this article, we introduced our sample application called “Hello Zoom”. This is a video conferencing application that allows us to join a meeting. We set the premise for building our cross platform application using Visual Studio. Our sample application will target four platforms: Windows, Mac, iOS, and Android. We will leverage .Visual Studio, NET and Xamarin.Forms to access the native capabilities of each underlying platform and achieve a significant amount of code reuse. In the next article, we will start development by creating our solution for building our application using Visual Studio.
Back when we started MILL5 I was asked “What are you doing?” “Are you starting a consulting company?” “Are you starting a product company?” “What are you trying to do?” “Why are you doing this?”
Back then [prior to MILL5] I would have told you that I was tired of unfulfilled promises, being overworked, and being generally taken advantage of. I was in a situation where I loved what I did, but I always felt like I was being limited in some way. I knew there was something better awaiting me.
For many years, I had been trying to start a company with my longtime friend, Shri Bhupathi. Shri and I had made several attempts over 14 years to work together only to have our day jobs get in the way. In late 2015, it became apparent that we had an opportunity to start MILL5. That is when we finally jumped at the chance to work with one another again. This time it was going to be on our terms.
Our goal was simple. Build a company that we would be happy to work at. We would build this new company based on a set of core principles.
Principle #1 – Hire good people and treat them like family
Every company says they want to hire good people. We are no exception. However, once we hire someone, we invest a lot of effort to ensure that they are treated like family.
You spend one-third or more of your work day with people other than your own family. You may even spend more time with your work colleagues than your own family. That is why it is important to us that each and every employee is treated well.
Principle #2 – Hire passionate people
If you are passionate about what you do, then you will always being having fun. This is such a simple concept, but so true. Your job is no longer work if you are doing what you love to do.
Principle #3 – Hire constant learners
Learning is engrained in our culture. People that are improving themselves by constantly learning new things are often on the forefront of technology. We believe this is the cornerstone of innovation for both our customers and for the products that we build.
Principle #4 – Hire unselfish people
We have seen the negative impact that a bad hire has on a company. Candidates need to be able to put others first. Successful candidates should clearly demonstrate that their priorities are company, team, self — in that order. This helps us weed out the “whiners, empire builders, and self-servers.”
Principle #5 – Empower people through better leadership
True leadership comes when you empower others. We believe in servant leadership which puts the needs of others first and helps people develop and perform as highly as possible.
Principle #6 – Don’t promise something you cannot deliver on
We have seen the negative impact of promises which are not met. That is why it is important to us that we deliver on promises that we make. It is also why we don’t make promises that we believe we cannot deliver on.
Principle #7 – Recognize and reward greatness
We do not believe in rewarding mediocrity. Showing up and doing your job is a requirement when you come to work. It is what happens when you, your team, or the company goes above and beyond and achieves greatness. This is when we want to recognize and reward people.
These principles have helped us build an amazing company in a very short period of time. In the next post we will cover what we have done to embody these principles.
I have been working with .NET since 2001. That is when I joined Microsoft and spent the next 10 years helping customers architect and build amazing applications on the .NET platform. Often my role is to lead a team of developers helping them build amazing software. Even though .NET has be around for many years, there are still developers that do not understand the use of IDisposable interface and the Finalize method. Proper understanding of the IDisposable interface and the Finalize method is critical to creating a good .NET application.
#1 – .NET manages memory for you
.NET provides a feature known as automatic memory management. Memory allocated by .NET [aka managed memory] does not need to be explicitly released. This frees developers from the tedious and difficult task of releasing memory.
Except for advanced scenarios, you should not be trying to manage memory. .NET manages memory for you through the use of garbage collection. The following article has a simple explanation of the garbage collector.
“The .NET garbage collector manages the allocation and release of memory for your application. Each time you create a new object, the common language runtime allocates memory for that object. The runtime continues to allocate memory for new objects. However, memory is not infinite. Eventually the garbage collector must perform a collection to free some memory. The garbage collector will determine the best time to perform a collection based on the allocations being made. That time is nondeterministic. When a collection occurs, the garbage collector will checks for objects that are no longer being used by your application and performs the necessary operations to reclaim memory.” – Garbage Collection, MSDN
What does this mean for you? Easy! You do nothing to manage memory because it is managed for you by the .NET garbage collector. Hence the term “managed memory”.
#2 – Know thy “unmanaged resource”
For the majority of the objects that you create [in .NET] you can rely on the .NET Framework’s garbage collector to handle memory management. While .NET manages memory for you, there are situations where you will use resources that are not allocated by .NET. These resources are referred to as “unmanaged resources”. Unmanaged resources are not allocated or managed by the .NET runtime.
The most common types of unmanaged resources are objects that wrap operating system resources, such as files, window handles, and network connections. Another common unmanaged resources used by developers are database connections. Two classes that use unmanaged resources are SqlConnection and FileStream. Each time you create and use an instance of either of these classes you are allocating unmanaged resources.
One potential way to identify a class that uses unmanaged resources is if they implement the IDisposable interface. The IDisposable interface provides a mechanism for releasing unmanaged resources. Unfortunately a class can use unmanaged resources without implementing IDisposable. Fortunately most classes in .NET that use unmanaged resources implement the IDisposable interface.
#3 – You are responsible for releasing unmanaged resources
The garbage collector was specifically designed to release managed memory and does not know about unmanaged resources. That means that anything not controlled by the garbage collector should be explicitly released.
So how does one explicitly release unmanaged resources?
The Common Language Runtime (CLR) provides a mechanism known as the Finalize method. The Finalize method (aka finalizer) provides a mechanism for objects to free resources and perform other cleanup operations before an object is reclaimed by the garbage collector. Any object that implements a finalizer is eligible to have their Finalize method called by the garbage collector. The garage collector will call the finalizer under the following conditions.
- When an objects is determined to be inaccessible by the garbage collector and the object has not become exempt for finalization by a prior call to the GC.SuppressFinalize method.
- During the shutdown of an application domain, unless the object is exempt from finalization. Any object that is accessible will have their Finalize method called at shutdown.
There are many limitations to using the Finalize method (see Object.Finalize for more details). The biggest limitation is that the time when the Finalize method is called is nondeterministic. To ensure deterministic release of unmanaged resources you need to provide an implementation of the IDisposable.Dispose method. When a developer calls your Dispose method it is your responsibility to release any unmanaged resources.
After reading this post you should come away with three key takeaways.
- .NET manages memory for you and you do not need to do anything to help the garbage collector or to manage memory.
- There are resources that are not managed by the .NET runtime. These resources are referred to as unmanaged resources.
- It is your responsibility to explicitly release unmanaged resources preferably by calling IDisposable.Dispose from your code.
This is the foundation from which we will build best practices for the proper use and implementation of the IDisposable interface and Finalize method. We will cover at least two more articles, “Myths About Garbage Collection” and “Proper Implementation of IDisposable”.
These articles were used in the creation of this blog post. I suggest that you read them once you are done reading this series.
- Dispose Pattern
- Implementing Finalize and Dispose to Clean Up Unmanaged Resources
- Object.Finalize Method()