Archive for the ‘Mono’ Category.

Reasons to use MonoTouch and MonoDroid

MonoTouch and MonoDroid allow us to write our apps in C# and this is the right solution for our mobile apps and here are the reasons why.

Note: These reasons were ones I provided to a C# shop so some may not be valid for places where the majority of developers are not C# developers.

  1. MonoTouch is native. See monotouch is both a wrapper for the native code and the ability to access C# libraries. It is not like flash or html 5, where it is completely different technology. It is just the ability to use native code from C# with an added C# framework.
  2. MonoTouch uses the native UI (and MonoDroid does too). So UX’s desire to have a native UI is met by MonoTouch.
  3. Many companies already use MonoTouch and MonoDroid: Microsoft, 3M, VMWare, Novartis, Target, Acenture, Cisco, AT&T, AOL, Monster, Cornell University, Raytheon, Intuit, HP, and many more companies.
  4. The number of C# language experts we have: All of us
    The number of Objective-C language experts we have: Zero
    With C# everybody can work on the code, not just one or two Objective C engineers.
  5. If we use Objective C, we will have a huge ramp up expense and this expense will occur over and over, because every time someone quits, it is more likely that we will have to incur the cost of training a C# developer to become an Objective C developer than it is likely we will hire. As you know, hiring a replacement may or may not happen.
  6. Shared C# code. A large portion of our code the code write for SharePoint, iOS, Windows, and Android can be used and unit tested in one place. I have personally experienced this re-use of code at my previous company. We starting an Android app and our project was finished more than three weeks early by using MonoDroid, because we were able to use all the C# code we had already written.
  7. C# is a more developed language and is far easer to write code in. For example, to connect to a web service using windows integrated security is just a few lines of code in C# but requires extra libraries and a massive amount of effort in Java or Objective C.
  8. Shared Unit Test libraries. Since much of the code is shared, separate unit tests are not needed. Also, the C# unit testing frameworks we are already familiar with can be used and there is no need to ramp up on and implement a new unit testing technology. This is just another cost saving.

I recommended MonoDroid and MonoTouch at LANDesk and I will do the same here. The cost of using Ojbective C is far greater and the time to market is far longer. The SDLC of Objective C will have a greater cost. Choosing it will be a costly.

Since this isn’t my team and since it isn’t my decision, this is the last I am going to say about it.

Running Pinta on FreeBSD – A C# (Mono) Image Editor

I wanted to continue with the C# (Mono) on FreeBSD theme this week. The next C# (Mono) post for FreeBSD is simply running a .C# (Mono) app on FreeBSD. My first thought was this, “I wonder if there is a mono version of Paint.NET?”. Paint.NET is my favorite image editor for Windows. After a quick search, I found the Pintaproject, which is a Mono clone of Paint.NET.

Installing Pinta on FreeBSD

So anyway, the steps for running on FreeBSD are quite simple.  This is a preview of my next FreeBSD Friday post, as I will continue the mono them to promote you app.

  1. Follow this post to get mono on FreeBSD.
    http://rhyous.com/2010/12/10/c-mono-on-freebsd/
  2. Download the Pinta tarball.
    Note: Get the latest link from here: http://pinta-project.com/download

    $ fetch http://cloud.github.com/downloads/PintaProject/Pinta/pinta-1.3.tar.gz
  3. Extract it:
    $ tar -xzf pinta-0.5.tar.gz
  4. Change to the directory:
    $ cd pinta-0.5
  5. Run configure.
    $ ./configure
  6. Note: I am not entirely sure this is needed, but I did it because it was there.

    $ mkdir ~/.tmp
  7. Compile the solution as follows:
    $ mdtool build Pinta.sln

    Note: I am not sure why, but “make” didn’t work, though I expected it to.

  8. Then as root or with sudo, run make install.
    # make install
  9. Make the shell rehash the commands in PATH.
    $ rehash
    Or depending on your shell...
    $ hash -r
  10. Now just run pinta.
     $ pinta

 

Pinta is now installed and usable on FreeBSD or PC-BSD.

More information

Pinta installs the following files

/usr/local/bin/pinta
/usr/local/lib/pinta/
/usr/local/lib/pinta/Pinta.Core.dll
/usr/local/lib/pinta/Pinta.Effects.dll
/usr/local/lib/pinta/Pinta.Gui.Widgets.dll
/usr/local/lib/pinta/Pinta.Resources.dll
/usr/local/lib/pinta/Pinta.Tools.dll
/usr/local/lib/pinta/Pinta.exe

The first file, /usr/local/bin/pinta, is a shell script that runs this:

#!/bin/sh
exec /usr/local/bin/mono /usr/local/lib/pinta/Pinta.exe "$@"

The other files are the application. It is a little weird to see .exe and .dll files on FreeBSD, but I’ll get over it.

Adding Pinta to the KDE Menu

I use KDE so I was able to add a menu item for pinta easily. I used the same command that the shell script used:

/usr/local/bin/mono /usr/local/lib/pinta/Pinta.exe "$@"

I found a nice installed logo and used it for the menu icon:
/usr/local/share/icons/hicolor/96×96/apps/pinta.png

Pinta in Ports

According to this Problem Report (PR), Pinta will be a port soon, if it isn’t already. http://www.freebsd.org/cgi/query-pr.cgi?pr=164309

A Hello World Android App in C#

This post is a continuation of Writing Android apps in C# using MonoDroid.

Writing your first MonoDroid project

Now that you have installed and configured MonoDroid and its prerequisites, you are ready to create your first project.

  1. Open Visual Studio.
  2. Go to File | New | Project.
  3. Choose “Mono for Android”. This is a new project type added by the Mono for Android Visual Studio 2010 Plugin.
  4. Give the project a name and click OK.

You now have a sample MonoDroid app.

Running your first MonoDroid App in an Emulator

Now that you have a sample MonoDroid app, learning to deploy it to an Android device and to test it is the next step.

  1. Simply press F5 in your “Mono for Android” Visual Studio project. The following screen appears however, there are no running Android devices.
  2. Click the link to “Start emulator image”.
  3. Wait until your Android emulator starts and you see the graphical display and not just a text display.
  4. Select your emulator from the Running Devices list and click OK.
  5. Wait. It is going to deploy the mono library to your emulator and deploy your app and this can take time.

You application should now be running in your Android emulator.

This is just a sample application that increments a counter and displays how many times you have click the button.

You are now ready to start writing your own application.

More Tutorials

Xamarin has multiple Tutorials to help you get a little further along.

MonoDroid Tutororials by Xamarin

Writing Android apps in C# using MonoDroid

As C# developers, many of us would prefer to write Android Apps in C# as well. Novell had promised us MonoDroid, but we were quite concerned as to whether MonoDroid would ever be released when Novell was dismantled.

However, Xamarin spawned from the ashes like a phoenix to restore the viability of MonoDroid, restoring our hopes to writing in C# for the Android platform.

Though I am hopeful that MonoDroid will become popular allowing C# to be a commonly used language for Android devices, there is still some question as to whether Xamarin and its MonoDroid product will survive.

Xamarin is a new company and needs to survive first. Its business is to sell MonoDroid, which is not open source, but is a proprietary product. Unfortunately, MonoDroid may cost too much, preventing adoption among app developers. Xamarin requires a customer base and a continual adoption rate if it is going to survive. If the company folds, what is going to happen to the library and the apps that use it?

Is Development with MonoDroid Free? Yes and No!

Yes and no.

Yes because anybody can use and develop with MonoDroid at no cost. It isn’t until you need to publish an app to the app store that you need to buy a license. You can use the MonoDroid trial for as long as you want. Here is a quote from the trial website. [2]

The evaluation version of Mono for Android does not expire, but enables development and testing against the Android Emulator only.

No, because you need to buy a license once either of the following become true:

  1. You need to test your code directly on a real device and not just an emulated device
  2. You are ready to publish an app to the app store

So what is the cost of MonoDroid? Depends on if you buy Professional, Enterprise, or Enterprise Priority. On the Xamarin store, the following table can be found. To see it you have to add MonoDroid to your cart and then click the “Show product comparison” link. [1]

ProfessionalEnterpriseEnterprise Priority
Deploy to your devicesHas this featureHas this featureHas this feature
Publish to app storesHas this featureHas this featureHas this feature
Enterprise distributionHas this featureHas this feature
Priority support queueHas this feature
Guaranteed response timeHas this feature
License expirationNeverNeverNever
Update subscription1 Year1 Year1 Year
License usageOriginal UserSeatSeat
Price (USD)$399$999$2,499

These costs are very low for business or enterprise customers who have C# developers and want to write Android apps.  The cost of training a C# developer to develop apps for Android in Java may be far greater than training them to develop apps for Android using C# and buying a MonoDroid license.

Is MonoDroid easy to set up?

Update
MonoDroid is not down to a one-click installer.

Here is the old method of Installing without the One-click Installer

MonoDroid is simple to set up.  Xamarin has some simple steps that can be found on their web site. They have MonoDroid installation instructions for installing MonoDroid for use with any of three environments.

  1. Visual Studio  (Important! Visual Studio Express is not supported)
  2. MonoDevelop on Windows
  3. MonoDevelop on Mac OSX

If you don’t have a Visual Studio license and you can’t afford one, then go with MonoDevelop because Visual Studio Express is noted to be enough [3].

However, the Visual Studio install is four simple steps.

  1. Install the Java SDK
  2. Install the Android SDK
  3. Configure your simulator
  4. Install the Mono for Android Visual Studio 2010 Plugin

These are very easy steps to complete, and I won’t repeat the steps here, but once you complete them, you are ready to start writing Android apps in C#.

Once you feel you have everything installed, click the following link to continue reading.

Writing your first MonoDroid project

http://android.xamarin.com/Installation/Windows

See my article on Mono in the BSD Magazine May issue

The BSD Magazine has released and there is an article in it by yours truly.

Check it out.

May issue of BSD magazine- Embedded BSD: FreeBSD and Alix

Installing the latest version of Mono on FreeBSD or How to install and use portshaker?

Mono is basically the .NET Framework on FreeBSD or other open source platforms. This allows development in C# on FreeBSD.  C# is an extremely popular language that is not slowing down.  It’s popularity stems from that fact that this language and its features allows for rapid development that is much faster than many other languages.

The version of Mono available in the ports tree is not the latest version available. Just like FreeBSD has a release version and a development version, Mono has a release version and a development version.  The development version is so much newer that it is hard not to recommend it over the release version.

Step 1 – Install the latest ports

This is already documented here:

How to install ports on FreeBSD?

Step 2 – Install portshaker and portshaker-config

The team at BSD# have a tool called portshaker that adds mono ports to the ports tree.  Install it as follows.

#
#
cd /usr/ports/ports-mgmt/portshaker-config
make BATCH=yes install

Note: Notice I didn’t just install portshaker, I installed portshaker-config which has portshaker as a dependency, so you get both installed with one command.

Step 3 – Configure portshaker

The example portshaker.conf.example is configured correctly for default configurations, so all we need to do is copy it.

# cp /usr/local/etc/portshaker.conf.example /usr/local/etc/portshaker.conf

Step 4 – Run portshaker

Yes, it is that easy.  Simply run portshaker.

# portshaker

Note: You may be prompted to merge a few files. I diffed and chose either install or continue each time.

Note: Running portshaker uses subversion to download so if you need to use an HTTP proxy, you have to configure subversion to use an HTTP proxy as it doesn’t use the FreeBSD HTTP_PROXY environment variable.

Your ports tree is now updated by portshaker.

Step 5 – Install mono

The mono port should now be updated to the latest version.

#
#
cd /usr/ports/lang/mono
make BATCH=yes install

Mono is now installed on your system.

There is an example of building a hello world app here:

C# (Mono) on FreeBSD

Asp.Net web services on FreeBSD and Apache using Mono

Asp.Net is cross platform using mono. Novell SUSE and Microsoft and others companies are dedicated to making .NET Framework a cross platform solution. Asp.Net web services are limited to running on windows, but can also run on other platforms, such as FreeBSD.

FreeBSD has ports for mono and mod_mono and can easily run web services build with Asp.Net. Here is a tutorial to make this happen.

Preparing a FreeBSD system for Asp.Net on Apache using Mono

Information

A good place to start reading is the getting started page on the mono project’s web site.:
http://mono-project.com/Start

This has the resources you need for most things, however, the documentation is designed mostly for SUSE Linux, so be prepared for slight differences on FreeBSD.

Step 1 – Install Apache

Install Apache on FreeBSD as follows.

  1. Change to the ports directory for Apache and run make install.
    #
    #
    cd /usr/ports/www/apache22
    make install
  2. Configure Apache to load on start up.
    #echo ‘apache22_enable=”YES”‘ >> /etc/rc.conf
  3. Leave Apache stopped. We will start it later.

Step 2 – Install mod_mono

Installing mod_mono will also install mono and xsp. Install mod_mono as follows.

  1. Change to the ports directory for Apache and run make install.
    #
    #
    cd /usr/ports/mod_mono
    make install
  2. Because on FreeBSD these packages work a little differently, you don’t need to do some of the steps listed on the mono website because they are done for you. Here are some key paths and differences in the packages on FreeBSD that you should know about.
    • The mod_mono port installs a mod_mono.conf file to /usr/local/etc/apache22/Includes which is automatically includes in the httpd.conf, so you don’t have to add an include manually.
    • The xsp port adds sample ASP.NET web services to /usr/local/lib/xsp.
    • The apache root directory is /usr/local/www/apache22/data
  3. Here are the contents of the mod_mono.conf file. Notice that this Apache include file loads a couple modules, adds a bunch of types, and adds a few files as DirectoryIndex options.
    # mod_mono.conf
    
    # Achtung! This file may be overwritten
    # Use 'include mod_mono.conf' from other configuration file
    # to load mod_mono module.
    
    <IfModule !mod_mono.c>
        LoadModule mono_module /usr/local/libexec/apache22/mod_mono.so
    </IfModule>
    
    <IfModule mod_headers.c>
        Header set X-Powered-By "Mono"
    </IfModule>
    
    AddType application/x-asp-net .aspx
    AddType application/x-asp-net .asmx
    AddType application/x-asp-net .ashx
    AddType application/x-asp-net .asax
    AddType application/x-asp-net .ascx
    AddType application/x-asp-net .soap
    AddType application/x-asp-net .rem
    AddType application/x-asp-net .axd
    AddType application/x-asp-net .cs
    AddType application/x-asp-net .vb
    AddType application/x-asp-net .master
    AddType application/x-asp-net .sitemap
    AddType application/x-asp-net .resources
    AddType application/x-asp-net .skin
    AddType application/x-asp-net .browser
    AddType application/x-asp-net .webinfo
    AddType application/x-asp-net .resx
    AddType application/x-asp-net .licx
    AddType application/x-asp-net .csproj
    AddType application/x-asp-net .vbproj
    AddType application/x-asp-net .config
    AddType application/x-asp-net .Config
    AddType application/x-asp-net .dll
    DirectoryIndex index.aspx
    DirectoryIndex Default.aspx
    DirectoryIndex default.aspx
    

Step 3 – Add the “test” web service to the Apache root directory

In /usr/local/lib/xsp, added by the mod_mono port, is a “test” folder that contains sample web services. Ther

  1. Copy /usr/local/lib/xsp/test to /usr/local/www/apache22/data.
    #cp -fR /usr/local/lib/xsp/test /usr/local/www/apache22/data/

Step 4 – Start Apache

  1. Start Apache with this command:
    #service apache22 start

You should now have Apache configured to run Asp.net.

Step 5 – Open the “test” folder in a browser

  1. Open your favorite browser on a workstation that has access to the server you just finished installing.
  2. Go to the URL of your server. For example, the url for my test server is this:
    http://192.168.0.43/test
  3. Browse around and test the web services.

Step 6 – Install Libraries as needed

    1. Determine if you need additional libraries.

With the bare minimum installed, you can almost guarantee that a web service is going to require a library you do not have installed. In fact, clicking on the second link in the “test” site, code-render.aspx, shows us this error.

Server Error in '/test' Application

gdiplus.dll

Description: HTTP 500. Error processing request.

Stack Trace:

System.DllNotFoundException: gdiplus.dll
  at (wrapper managed-to-native) System.Drawing.GDIPlus:GdiplusStartup (ulong&,System.Drawing.GdiplusStartupInput&,System.Drawing.GdiplusStartupOutput&)
  at System.Drawing.GDIPlus..cctor () [0x00000] in <filename unknown>:0

Version information: Mono Runtime Version: 2.6.7 (tarball Tue Mar 1 06:10:28 MST 2011); ASP.NET Version: 2.0.50727.1433

This library can be found and installed.

  1. Go to the directory for the port and run make install.
    #
    #
    cd /usr/ports/x11-toolkits/libgdiplus
    make BATCH=yes install

    This has some Xorg dependencies so compiling it could take a while. Notice the BATCH=yes parameter passed to make above. This will prevent any prompts and accept the defaults for every port this command compiles.

C# DataMeasurement object for comparing, converting, and adding or substracting data sizes

I created a C# DataMeasurement object a while ago but recently really started to use it. I wrote unit tests for it and fixed comparison and add/substract of nulls and wrote Unit tests for it.

The intent of the object is to be able to use any Data size and do the following:

  1. Convert it to any other data size type, 1 GB converts to 1024 MB.
  2. Compare it to any other data size type, 1 GB = 1024 MB.
  3. Add any other data size type and have it add correctly, 1 GB + 1024 MB = 2GB.

So you can easily compare things like 12343 bytes.

You can create the object in a lot of different ways as I have multiple constructors, and it is easy to add your own constructor.

Here is the object:

using System;
using System.Collections.Generic;
using System.Text;

namespace LANDesk.Install.Common
{
    public class DataMeasurement
    {
        #region Member Variables
        // This is the size in the current type. For example, 1 GB = 1.0. But
        // if you convert the Type to Megabyte, the value should change to 1024.0;
        protected Double _DataSize;  
        protected DataType _DataType;
        #endregion

        #region Constructors

        /// <summary>
        /// The default constructor.  This initializes and object with a
        /// DataSize of 0 and a DataType of Byte.
        /// </summary>
        public DataMeasurement()
        {
            _DataSize = 0;
            _DataType = DataType.Byte;
        }

        /// <summary>
        /// This constructor takes a value and assumes the data measurement
        /// type is in bytes.
        /// </summary>
        /// <param name="inValue">The measurement value as a ulong.</param>
        public DataMeasurement(UInt64 inSizeInBytes)
        {
            _DataType = DataType.Byte;
            _DataSize = inSizeInBytes * 8;
        }

        /// <summary>
        /// This constructor takes a value and a data measurement type.
        /// </summary>
        /// <param name="inValue">The measurement value as a ulong.</param>
        /// <param name="inType">The measurement type.</param>
        public DataMeasurement(UInt64 inValue, DataType inType)
        {
            _DataType = inType;
            _DataSize = inValue;
        }

        /// <summary>
        /// This constructor takes a double value and defaults to megabyte.
        /// </summary>
        /// <param name="inValue"></param>
        public DataMeasurement(double inValue)
        {
            _DataType = DataType.Megabyte;
            _DataSize = inValue;
        }

        /// <summary>
        /// This constructor takes a value and a data measurement type.
        /// </summary>
        /// <param name="inValue">The measurement value as a double.</param>
        /// <param name="inType">The measurement type.</param>
        public DataMeasurement(double inValue, DataType inType)
        {
            _DataType = inType;
            _DataSize = inValue;
        }

        /// <summary>
        /// This constructor takes a value and a data measurement type.
        /// </summary>
        /// <param name="inValue">The measurement value as a double.</param>
        /// <param name="inType">The measurement type as a string, "GB", "Gigabyte".</param>
        public DataMeasurement(UInt64 inValue, String inType)
        {
            _DataSize = inValue;
            GetDataTypeFromString(inType);
        }

        /// <summary>
        /// This constructor takes a string representation of a data measurement.
        /// </summary>
        /// <param name="inValueAndType">The measurement value and type in a  
        /// single string such as "49 GB" or "49 GBSI" or "49 Gigabyte". There
        /// must be a space as it is used to split the value from the type, so 
        ///  "49GB" is invalid because there is no space delimeter.</param>
        public DataMeasurement(String inValueAndType)
        {
            char[] split = { ' ' };
            String[] data = inValueAndType.Split(split);
            _DataSize = Convert.ToUInt64(data[0]);
            GetDataTypeFromString(data[1]);
        }
        #endregion

        #region Properties
        public Double Size
        {
            get { return _DataSize; }
            set { _DataSize = value; }
        }

        public DataType DataSizeType
        {
            get { return _DataType; }
            set { _DataType = value; }
        }

        public ShortName DataSizeTypeShortName
        {
            get { return (ShortName)_DataType; }
            set { _DataType = (DataType)value; }
        }

        public ulong Bit
        {
            get { return (ulong)ConvertToType(DataType.Bit, false); }
            set
            {
                _DataType = DataType.Bit;
                _DataSize = value;
            }
        }

        public Double Byte
        {
            get { return ConvertToType(DataType.Byte, false); }
            set
            {
                _DataType = DataType.Byte;
                _DataSize = value;
            }
        }

        public Double KilobitSI
        {
            get { return ConvertToType(DataType.KilobitSI, false); }
            set
            {
                _DataType = DataType.KilobitSI;
                _DataSize = value;
            }
        }

        public Double Kilobit
        {
            get { return ConvertToType(DataType.Kilobit, false); }
            set
            {
                _DataType = DataType.Kilobit;
                _DataSize = value;
            }
        }
        public Double KilobyteSI
        {
            get { return ConvertToType(DataType.KilobyteSI, false); }
            set
            {
                _DataType = DataType.KilobyteSI;
                _DataSize = value;
            }
        }

        public Double Kilobyte
        {
            get { return ConvertToType(DataType.Kilobyte, false); }
            set
            {
                _DataType = DataType.Kilobit;
                _DataSize = value;
            }
        }

        public Double MegabitSI
        {
            get { return ConvertToType(DataType.MegabitSI, false); }
            set
            {
                _DataType = DataType.MegabitSI;
                _DataSize = value;
            }
        }

        public Double Megabit
        {
            get { return ConvertToType(DataType.Megabit, false); }
            set
            {
                _DataType = DataType.Megabit;
                _DataSize = value;
            }
        }
        public Double MegabyteSI
        {
            get { return ConvertToType(DataType.MegabyteSI, false); }
            set
            {
                _DataType = DataType.MegabyteSI;
                _DataSize = value;
            }
        }

        public Double Megabyte
        {
            get { return ConvertToType(DataType.Megabyte, false); }
            set
            {
                _DataType = DataType.Megabyte;
                _DataSize = value;
            }
        }

        public Double GigabitSI
        {
            get { return ConvertToType(DataType.GigabitSI, false); }
            set
            {
                _DataType = DataType.GigabitSI;
                _DataSize = value;
            }
        }

        public Double Gigabit
        {
            get { return ConvertToType(DataType.Gigabit, false); }
            set
            {
                _DataType = DataType.Gigabit;
                _DataSize = value;
            }
        }
        public Double GigabyteSI
        {
            get { return ConvertToType(DataType.GigabyteSI, false); }
            set
            {
                _DataType = DataType.GigabyteSI;
                _DataSize = value;
            }
        }

        public Double Gigabyte
        {
            get { return ConvertToType(DataType.Gigabyte, false); }
            set
            {
                _DataType = DataType.Gigabyte;
                _DataSize = value;
            }
        }

        public Double TerabitSI
        {
            get { return ConvertToType(DataType.TerabitSI, false); }
            set
            {
                _DataType = DataType.TerabitSI;
                _DataSize = value;
            }
        }

        public Double Terabit
        {
            get { return ConvertToType(DataType.Terabit, false); }
            set
            {
                _DataType = DataType.Terabit;
                _DataSize = value;
            }
        }
        public Double TerabyteSI
        {
            get { return ConvertToType(DataType.TerabyteSI, false); }
            set
            {
                _DataType = DataType.TerabyteSI;
                _DataSize = value;
            }
        }

        public Double Terabyte
        {
            get { return ConvertToType(DataType.Terabyte, false); }
            set
            {
                _DataType = DataType.Terabyte;
                _DataSize = value;
            }
        }

        public Double PetabitSI
        {
            get { return ConvertToType(DataType.PetabitSI, false); }
            set
            {
                _DataType = DataType.PetabitSI;
                _DataSize = value;
            }
        }

        public Double Petabit
        {
            get { return ConvertToType(DataType.Petabit, false); }
            set
            {
                _DataType = DataType.Petabit;
                _DataSize = value;
            }
        }
        public Double PetabyteSI
        {
            get { return ConvertToType(DataType.PetabyteSI, false); }
            set
            {
                _DataType = DataType.PetabyteSI;
                _DataSize = value;
            }
        }

        public Double Petabyte
        {
            get { return ConvertToType(DataType.Petabyte, false); }
            set
            {
                _DataType = DataType.Petabyte;
                _DataSize = value;
            }
        }

        public Double ExabitSI
        {
            get { return ConvertToType(DataType.ExabitSI, false); }
            set
            {
                _DataType = DataType.ExabitSI;
                _DataSize = value;
            }
        }

        public Double Exabit
        {
            get { return ConvertToType(DataType.Exabit, false); }
            set
            {
                _DataType = DataType.Exabit;
                _DataSize = value;
            }
        }

        public Double ExabyteSI
        {
            get { return ConvertToType(DataType.ExabyteSI, false); }
            set
            {
                _DataType = DataType.ExabyteSI;
                _DataSize = value;
            }
        }

        public Double Exabyte
        {
            get { return ConvertToType(DataType.Exabyte, false); }
            set
            {
                _DataType = DataType.Exabyte;
                _DataSize = value;
            }
        }
        #endregion

        #region Functions
        /// <summary>
        /// Writes the DataMeasurement to string, such as "1 GB" or "1024 KB".
        /// It always uses the DataSize and DataType values.
        /// </summary>
        override public string ToString()
        {
            return String.Format("{0} {1}", _DataSize, ((ShortName)_DataType).ToString());
        }

        /// <summary>
        /// Writes the DataMeasurement to string, such as "1 GB" or "1024 KB".
        /// However, it does so in the DataType that you specify.
        /// </summary>
        /// <param name="inDataType">The type to output to string. For example
        /// If the measurement is "4 Gigabyte" but you pass in Megabyte, it 
        /// will output "4096 MB".</param>
        /// <returns></returns>
        public string ToString(DataType inDataType)
        {
            Double size = ConvertToType(inDataType, false);
            return String.Format("{0} {1}", size, ((ShortName)inDataType).ToString());
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            DataMeasurement right = obj as DataMeasurement;
            if ((object)right == null)
                return false;

            return this == right;
        }

        private void GetDataTypeFromString(String inType)
        {
            if (inType.Length == 2 || inType.Length == 4)
            {   // Short name was used so get the ShortName and case it to a DataType
                // KB and Kb are not the same, so case is Important
                _DataType = (DataType)Enum.Parse(typeof(ShortName), inType, false);
            }
            else
            {   // Long name was used so get 
                // We can ignore case because Kilobit and Kilobyte are different.
                _DataType = (DataType)Enum.Parse(typeof(DataType), inType, true);
            }
        }

        /// <summary>
        /// This function converts the stored measurement from its current
        /// value to a new value using the new DataType.
        /// </summary>
        /// <param name="inNewType">The new DataType. For example If the
        /// measurement is "4 Gigabyte" but you pass in Megabyte, it will
        /// change the value to "4096 Megabyte".</param>
        /// <returns>The new DataSize for the new type is returned.</returns>
        public Double ConvertToType(DataType inNewType)
        {
            return ConvertToType(inNewType, true);
        }

        /// <summary>
        /// This function converts the stored measurement from its current
        /// value to a new value using the new DataType.
        /// </summary>
        /// <param name="inNewType">The new DataType. For example If the
        /// measurement is "4 Gigabyte" but you pass in Megabyte, it will
        /// change the value to "4096 Megabyte".</param>
        /// <param name="inChangeObjectMeasurementType">A bool value that
        /// specifies whether to change the whole object.</param>
        /// <returns>The new DataSize for the new type is returned.</returns>
        public Double ConvertToType(DataType inNewType, bool inChangeObjectMeasurementType)
        {
            double ret = 0;
            bool isSet = false;
            if (inNewType == _DataType)
            {
                ret = _DataSize;
                isSet = true;
            }
            else if (inNewType == DataType.Bit)
            {
                ret = (ulong)_DataType * _DataSize * 8;
                isSet = true;
            }
            else if (_DataType == DataType.Bit)
            {
                ret = _DataSize / 8 / (ulong)inNewType;
                isSet = true;
            }
            
            if (!isSet)
                ret = (ulong)_DataType * _DataSize / (ulong)inNewType;

            if (inChangeObjectMeasurementType)
            {
                _DataType = inNewType;
                Size = ret;
            }

            return ret;
        }
        #endregion

        #region Operator Override Functions
        public static bool operator ==(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return true;
            if (null == (object)right || null == (object)left)
                return false;

            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size == right.Size;
            }
            else
            {
                return left.Byte == right.Byte;
            }
        }

        public static bool operator !=(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return false;
            if (null == (object)right || null == (object)left)
                return true;

            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size != right.Size;
            }
            else
            {
                return left.Byte != right.Byte;
            }
        }

        public static bool operator >(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return false;
            if (null == (object)right)
                return true;
            if (null == (object)left)
                return false;

            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size > right.Size;
            }
            else
            {
                return left.Byte > right.Byte;
            }
        }

        public static bool operator >=(DataMeasurement left, DataMeasurement right)
        {
            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size >= right.Size;
            }
            else
            {
                return left.Byte >= right.Byte;
            }
        }

        public static bool operator <(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return false;
            if (null == (object)right)
                return false;
            if (null == (object)left)
                return true;
            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size < right.Size;
            }
            else
            {
                return left.Byte < right.Byte;
            }
        }

        public static bool operator <=(DataMeasurement left, DataMeasurement right)
        {
            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size <= right.Size;
            }
            else
            {
                return left.Byte <= right.Byte;
            }
        }

        public static DataMeasurement operator +(DataMeasurement left, DataMeasurement right)
        {
            return left + right.ConvertToType(left.DataSizeType, false);
        }

        public static DataMeasurement operator +(DataMeasurement left, double right)
        {
            if ((null == (object)left && null == (object)right) || null == (object)right)
                return left;
            if (null == (object)left)
                return new DataMeasurement(right);
            return new DataMeasurement(left.Size + right, left.DataSizeType);
        }

        public static DataMeasurement operator -(DataMeasurement left, DataMeasurement right)
        {
            return left - right.ConvertToType(left.DataSizeType, false);
        }

        public static DataMeasurement operator -(DataMeasurement left, double right)
        {
            if ((null == (object)left && null == (object)right) || null == (object)right)
                return left;
            if (null == (object)left)
                return new DataMeasurement(right);
            return new DataMeasurement(left.Size - right, left.DataSizeType);
        }
        #endregion

        #region Enums
        public enum ShortName : ulong
        {
            b = 0, // Bit must be handled special
            // Everything after is in bytes
            B = 1,
            KbSI = 125,
            Kb = 128,
            KBSI = 1000,
            KB = 1024,
            MbSI = 125000,
            Mb = 131072,
            MBSI = 1000000,
            MB = 1048576,
            GbSI = 125000000,
            Gb = 134217728,
            GBSI = 1000000000,
            GB = 1073741824,
            TbSI = 125000000000,
            Tb = 137438953472,
            TBSI = 1000000000000,
            TB = 1099511627776,
            PbSI = 125000000000000,
            Pb = 140737488355328,
            PBSI = 1000000000000000,
            PB = 1125899906842624,
            EbSI = 125000000000000000,
            Eb = 144115188075855872,
            EBSI = 1000000000000000000,
            EB = 1152921504606846976
        }

        public enum DataType : ulong
        {
            Bit = 0, // Bit must be handled special
            // Everything after is in bytes
            Byte = 1,
            KilobitSI = 125,
            Kilobit = 128,
            KilobyteSI = 1000,
            Kilobyte = 1024,
            MegabitSI = 125000,
            Megabit = 131072,
            MegabyteSI = 1000000,
            Megabyte = 1048576,
            GigabitSI = 125000000,
            Gigabit = 134217728,
            GigabyteSI = 1000000000,
            Gigabyte = 1073741824,
            TerabitSI = 125000000000,
            Terabit = 137438953472,
            TerabyteSI = 1000000000000,
            Terabyte = 1099511627776,
            PetabitSI = 125000000000000,
            Petabit = 140737488355328,
            PetabyteSI = 1000000000000000,
            Petabyte = 1125899906842624,
            ExabitSI = 125000000000000000,
            Exabit = 144115188075855872,
            ExabyteSI = 1000000000000000000,
            Exabyte = 1152921504606846976
        }
        #endregion
    }
}

I could probably do a better job of testing this. Here is a test class that succeeds. If you want more testing add it.

Hopefully this helps you out.

using LANDesk.Install.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace LANDesk.Install.Common.Tests
{
    /// <summary>
    ///This is a test class for DataMeasurementTest and is intended
    ///to contain all DataMeasurementTest Unit Tests
    ///</summary>
    [TestClass()]
    public class DataMeasurementTest
    {
        List<DataMeasurement> sizes = new List<DataMeasurement>();

        [TestMethod()]
        public void DataMeasurementTestAdditionAndGreaterThanLessThan()
        {
            DataMeasurementEqualityTest();
            DataMeasurement OneGB = new DataMeasurement("1 GB");
            DataMeasurement OneGBinMB = new DataMeasurement("1024 MB");
            DataMeasurement twoGB = new DataMeasurement(2, DataMeasurement.DataType.Gigabyte);
            DataMeasurement twoGBadded = OneGB + OneGBinMB;
            TestEqualValues(twoGB, twoGBadded);

            foreach (DataMeasurement dm in sizes)
            {
                TestLeftIsGreater(twoGB, dm);
                TestRightIsGreater(dm, twoGB);
            }
        }

        [TestMethod()]
        public void DataMeasurementTestSubtractionAndGreaterThanLessThan()
        {
            DataMeasurementEqualityTest();
            DataMeasurement tenGB = new DataMeasurement(10, DataMeasurement.DataType.Gigabyte);
            DataMeasurement NineGB = new DataMeasurement(9, DataMeasurement.DataType.Gigabyte);
            DataMeasurement NineGBbySubtraction = tenGB - sizes[0];
            TestEqualValues(NineGB, NineGBbySubtraction);
            TestLeftIsGreater(tenGB, NineGB);
            TestLeftIsGreater(tenGB, NineGBbySubtraction);
            TestRightIsGreater(NineGB, tenGB);
            TestRightIsGreater(NineGBbySubtraction, tenGB);
        }
        
        [TestMethod()]
        public void TestConversion()
        {
            DataMeasurement dm = new DataMeasurement("4 GB");
            dm.ConvertToType(DataMeasurement.DataType.Megabyte);
            Assert.IsTrue(dm.Size == (double)4096);
            Assert.IsTrue(dm.ToString() == "4096 MB");            
        }

        [TestMethod()]
        public void DataMeasurementOtherTest()
        {
            sizes = new List<DataMeasurement>();
            int i = -1;

            // Test 1 - Check that conversion is working
            i++;
            sizes.Add(new DataMeasurement("1024 bit"));
            Assert.IsTrue(sizes[i].Bit == 1024, "Test 1, to Bit.");
            Assert.IsTrue(sizes[i].Byte == 1024 / 8, "Test 1, to Byte.");
            double expected = 1024 / 8 / 1024.0;
            Assert.IsTrue(sizes[i].Kilobyte == expected, "Test 1, " + sizes[i].Kilobyte + " should equal " + expected);

            // Test 2 - Check that conversion is working
            i++;
            sizes.Add(new DataMeasurement(4, DataMeasurement.DataType.Gigabyte));
            Assert.IsTrue(sizes[i].Bit == 34359738368, "Test 2, to bit.");
            Assert.IsTrue(sizes[i].Byte == 4294967296, "Test 2, to Byte.");
            Assert.IsTrue(sizes[i].Kilobyte == 4 * 1024 * 1024, "Test 2, to Kilobyte.");
            expected = 4.0 / 1024;
            Assert.IsTrue(sizes[i].Terabyte == expected, "Test 2, " + sizes[i].Terabyte + " should equal " + expected);

            // Test 3 - Comparisons
            Assert.IsTrue(sizes[i - 1] < sizes[i], "Test 3, " + sizes[i - 1] + " is less than " + sizes[i]);
            Assert.IsTrue(sizes[i - 1] <= sizes[i], "Test 3, " + sizes[i - 1] + " is less than or equal to " + sizes[i]);
            Assert.IsFalse(sizes[i - 1] > sizes[i], "Test 3, " + sizes[i - 1] + " is greater than " + sizes[i]);
            Assert.IsFalse(sizes[i - 1] >= sizes[i], "Test 3, " + sizes[i - 1] + " is greater than or equal to " + sizes[i]);
            Assert.IsFalse(sizes[i - 1] == sizes[i], "Test 3, " + sizes[i - 1] + " is equal to " + sizes[i]);
            Assert.IsTrue(sizes[i - 1] != sizes[i], "Test 3, " + sizes[i - 1] + " is not equal to " + sizes[i]);
        }

        public void DataMeasurementEqualityTest()
        {
            DataMeasurement last = null;
            DataMeasurement OneGB = new DataMeasurement("1 GB");
            foreach (DataMeasurement.DataType dt in Enum.GetValues(typeof(DataMeasurement.DataType)))
            {
                DataMeasurement next = new DataMeasurement(OneGB.ConvertToType(dt, false), dt);
                sizes.Add(next);
                if (last != null)
                    TestEqualValues(next, last);
                last = next;
            }
        }

        private void TestEqualValues(DataMeasurement left, DataMeasurement right)
        {
            Assert.IsFalse(left > right);
            Assert.IsFalse(left < right);
            Assert.IsTrue(left >= right);
            Assert.IsTrue(left <= right);
            Assert.IsTrue(left == right);
            Assert.IsFalse(left != right);
            Assert.IsTrue(left.Equals(right));
        }

        private void TestLeftIsGreater(DataMeasurement left, DataMeasurement right)
        {
            Assert.IsTrue(left > right);
            Assert.IsFalse(left < right);
            Assert.IsTrue(left >= right);
            Assert.IsFalse(left <= right);
            Assert.IsFalse(left == right);
            Assert.IsTrue(left != right);
        }

        private void TestRightIsGreater(DataMeasurement left, DataMeasurement right)
        {
            Assert.IsFalse(left > right);
            Assert.IsTrue(left < right);
            Assert.IsFalse(left >= right);
            Assert.IsTrue(left <= right);
            Assert.IsFalse(left == right);
            Assert.IsTrue(left != right);
        }
    }
}

I hope this object helps save you time.

C# Random Password Generator

BSD#

I needed to generate a random password in C# and I wanted to do it right.

I consulted a security expert and he mentioned that I should use a seed created with RNGCryptoServiceProvider so I did a search and quickly found this blog entry that had a good start.
http://eyeung003.blogspot.com/2010/09/c-random-password-generator.html

However, I needed three enhancements to this code.

  1. Store the password as a SecureString.
  2. Make upper case and lower case characters separate options.
  3. Guarantee that each character option would be used.

So I added these enhancements. Here are some notes about the enhancements:

  • SecureString – Since most password code requires strings instead of secure strings, even code such as a SQL connection strings, I cannot fault the original writer for leaving the password as a string. However, passwords should be stored as SecureString objects as much as possible. With my enhancements, it still flips back and forth between secure string and string, but hopefully is a SecureString as often as possible.
  • I include the ability to convert the SecureString to a string, because of the issue mentions in the previous bullet point.
  • I separated the character options. I also added back the characters that were listed as confusing. If someone thinks these are confusing, use a font where they are not confusing or remove them again.
  • Using all options – I guarantee that each option is used. The first characters in the password are chosen, one from each option, in a random order. I still didn’t like that, I created a scramble but in order to create the scramble, I had pull the password out as a string to get each character to scramble.
  • I also added some exception objects to make exceptions clear if there are any.
  • I also tested this on C# (Mono) on FreeBSD and it works.

Ok, here is the new version that includes my enhancements to the original code.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;

namespace System.Security
{
    public enum CharacterTypes : byte
    {
        Alpha_Lower = 1,
        Alpha_Upper = 2,
        Alpha_Upper_and_Lower = 3,
        Digit = 4,
        AlphaLowerNumeric = Digit + Alpha_Lower,        //  5 (4+1)
        AlphaUpperNumeric = Digit + Alpha_Upper,        //  6 (4+2)
        AlphaNumeric = Alpha_Upper_and_Lower + Digit,   //  7 (4+3)
        Special = 8,
        // You could add more character types here such as Alpha_Lower  + Special, but why?
        AlphaNumericSpecial = AlphaNumeric + Special    // 15 (8+7)
    }

    public class RandomPasswordGenerator
    {
        // Define default password length.
        private static int DEFAULT_PASSWORD_LENGTH = 16;

        private static PasswordOption AlphaLC = new PasswordOption() { Characters = "abcdefghijklmnopqrstuvwxyz", Count = 0 };
        private static PasswordOption AlphaUC = new PasswordOption() { Characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", Count = 0 };
        private static PasswordOption Digits = new PasswordOption() { Characters = "0123456789", Count = 0 };
        private static PasswordOption Specials = new PasswordOption() { Characters = "!@#$%^&*()~<>?", Count = 0 };

        #region Overloads

        /// <summary>
        /// Generates a random password with the default length.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate()
        {
            return Generate(DEFAULT_PASSWORD_LENGTH,
                            CharacterTypes.AlphaNumericSpecial);
        }

        /// <summary>
        /// Generates a random password with the default length.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate(CharacterTypes option)
        {
            return Generate(DEFAULT_PASSWORD_LENGTH, option);
        }

        /// <summary>
        /// Generates a random password with the specified length.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate(int passwordLength)
        {
            return Generate(passwordLength,
                            CharacterTypes.AlphaNumericSpecial);
        }

        /// <summary>
        /// Generates a random password.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate(int passwordLength,
                                      CharacterTypes option)
        {
            return GeneratePassword(passwordLength, option);
        }

        #endregion

        /// <summary>
        /// Generates the password.
        /// </summary>
        /// <returns></returns>
        private static SecureString GeneratePassword(int passwordLength, CharacterTypes option)
        {
            // Password length must at lest be 1 character long
            if (passwordLength < 1)
                throw new InvalidPasswordLengthException();

            // Character type must be a valid CharacterType
            if (option < CharacterTypes.Alpha_Lower || option > CharacterTypes.AlphaNumericSpecial)
                throw new InvalidPasswordCharacterTypeException();

            PasswordOptions passwordOptions = GetCharacters(option);

            // Make sure the password is long enough.
            // For example CharacterTypes.AlphaNumericSpecial
            // requires at least 4 characters: 1 upper, 1 lower, 1 digit, 1 special
            if (passwordLength < passwordOptions.Count)
                throw new InvalidPasswordLengthException();

            SecureString securePassword = new SecureString();
            string passwordChars = String.Empty;

            foreach (PasswordOption po in passwordOptions)
            {
                passwordChars += po.Characters;
            }

            if (string.IsNullOrEmpty(passwordChars))
                return null;

            var random = RandomSeedGenerator.GetRandom();

            for (int i = 0; i < passwordLength; i++)
            {
                int index;
                char passwordChar;
                if (!passwordOptions.AllOptionsAreUsed)
                {
                    PasswordOption po = passwordOptions.GetUnusedOption();
                    index = random.Next(po.Characters.Length);
                    passwordChar = po.Characters&#91;index&#93;;
                }
                else
                {
                    index = random.Next(passwordChars.Length);
                    passwordChar = passwordChars&#91;index&#93;;
                }

                securePassword.AppendChar(passwordChar);
            }

            return securePassword;
        }

        private int GetOptionsUsed()
        {
            int ret = 0;
            foreach (CharacterTypes option in Enum.GetValues(typeof(CharacterTypes)))
            {

            }
            return ret;
        }

        /// <summary>
        /// Gets the characters selected by the option
        /// </summary>
        /// <returns></returns>
        private static PasswordOptions GetCharacters(CharacterTypes option)
        {
            PasswordOptions list = new PasswordOptions();
            switch (option)
            {
                case CharacterTypes.Alpha_Lower:
                    list.Add(AlphaLC);
                    break;
                case CharacterTypes.Alpha_Upper:
                    list.Add(AlphaUC);
                    break;
                case CharacterTypes.Alpha_Upper_and_Lower:
                    list.Add(AlphaLC);
                    list.Add(AlphaUC);
                    break;
                case CharacterTypes.Digit:
                    list.Add(Digits);
                    break;
                case CharacterTypes.AlphaNumeric:
                    list.Add(AlphaLC);
                    list.Add(AlphaUC);
                    list.Add(Digits);
                    break;
                case CharacterTypes.Special:
                    list.Add(Specials);
                    break;
                case CharacterTypes.AlphaNumericSpecial:
                    list.Add(AlphaLC);
                    list.Add(AlphaUC);
                    list.Add(Digits);
                    list.Add(Specials);
                    break;
                default:
                    break;
            }
            return list;
        }
    }

    public static class RandomSeedGenerator
    {
        /// <summary>
        /// Gets a random object with a real random seed
        /// </summary>
        /// <returns></returns>
        public static Random GetRandom()
        {
            // Use a 4-byte array to fill it with random bytes and convert it then
            // to an integer value.
            byte[] randomBytes = new byte[4];

            // Generate 4 random bytes.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(randomBytes);

            // Convert 4 bytes into a 32-bit integer value.
            int seed = (randomBytes[0] & 0x7f) << 24 |
                        randomBytes&#91;1&#93; << 16 |
                        randomBytes&#91;2&#93; << 8 |
                        randomBytes&#91;3&#93;;

            // Now, this is real randomization.
            return new Random(seed);
        }
    }

    public class PasswordOption
    {
        public int Count { get; set; }
        public String Characters { get; set; }
    }

    public class PasswordOptions : List<PasswordOption>
    {
        public bool AllOptionsAreUsed
        {
            get
            {
                foreach (PasswordOption po in this)
                {
                    if (po.Count < 1)
                        return false;
                }
                return true;
            }
        }

        public PasswordOption GetUnusedOption()
        {
            PasswordOptions options = new PasswordOptions();
            foreach (PasswordOption po in this)
            {
                if (po.Count < 1)
                    options.Add(po);
            }
            if (options.Count < 1)
                return null;

            var random = RandomSeedGenerator.GetRandom();
            int optionIndex = random.Next(options.Count);
            return options&#91;optionIndex&#93;;
        }
    }

    public class InvalidPasswordLengthException : ArgumentException { }
    public class InvalidPasswordCharacterTypeException : ArgumentException { }

    public static class SecureStringExtender
    {
        public static string ConvertToPlainTextString(this SecureString securePassword)
        {
            if (securePassword == null)
                throw new ArgumentNullException("securePassword");

            IntPtr unmanagedString = IntPtr.Zero;
            try
            {
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
                return Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
            }
        }

        public static SecureString Scramble(this SecureString securePassword)
        {
            SecureString retSS = securePassword;
            Random random = RandomSeedGenerator.GetRandom();
            int moves = random.Next(securePassword.Length, securePassword.Length * 2);
            for (int i = 0; i < moves; i++)
            {
                int origIndex = random.Next(securePassword.Length);
                int newIndex = random.Next(securePassword.Length);
                char c = retSS.GetAt(origIndex);
                retSS.InsertAt(newIndex, c);
            }
            return retSS;
        }

        public static Char GetAt(this SecureString securePassword, int index)
        {
            if (securePassword.Length < index)
                throw new ArgumentException("The index parameter must not be greater than the string's length.");
            if (index < 0)
                throw new ArgumentException("The index must be 0 or greater.");
            return securePassword.ConvertToPlainTextString().Substring(index, 1).ToCharArray()&#91;0&#93;;
        }
    }
}
&#91;/sourcecode&#93;

Now if you want to make a simple command line executable that uses the code above, just create a new console project and call this line:

<code>Console.WriteLine(RandomPasswordGenerator.Generate().ConvertToPlainTextString());</code>

I added more code to handle command line parameters.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;

namespace ConsoleApplication2
{
    class Program
    {
        private static int PasswordLength;
        private static String Characters;

        static void Main(string[] args)
        {
            if (args.Length > 2)
            {
                ShowArgs();
                return;
            }

            if (args.Length > 0)
            {
                foreach (char c in args[0])
                {
                    if (char.IsDigit(c))
                    {
                        ShowArgs();
                        return;
                    }
                }
                PasswordLength = Convert.ToInt32(args[0]);
            }

            if (args.Length == 2)
                Characters = args[1];

            Console.WriteLine(RandomPasswordGenerator.Generate().ConvertToPlainTextString());
        }

        private static void ShowArgs()
        {
            String fullExeNameAndPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            String ExeName = System.IO.Path.GetFileName(fullExeNameAndPath);

            Console.WriteLine("Usage: " + ExeName + " [int] [string]");
            Console.WriteLine("[int] - The length of the password.  By default it is 11.");
            Console.WriteLine("[string] - The characters to use for the password.  By default it is alphanumeric case sensitive.");
        }
}

Hope you find this helpful. If you find flaws, please comment!

C# (Mono) – Reading and writing to a text file

C# (Mono) on FreeBSD
File access is made simple with C# (Mono) on FreeBSD.

Reading a text file with C# (Mono)

To read a file, use a StreamReader object. However, it is easy if you don’t do a new StreamWriter("File.txt") but instead use File.OpenText("File.txt") to create the StreamReader. Once you have the stream, you just need to run the stream’s ReadToEnd() function.

Here is a snippet to read a text file as a string.

// Open the file into a StreamReader
StreamReader file = File.OpenText("SomeFile.txt");
// Read the file into a string
string s = file.ReadToEnd();

Now that you have the text file as a string, you can manipulate the string as you desire.

Writing to a text file with C# (Mono)

To write a text file, use StreamWriter.

string str = "Some text";
// Hook a write to the text file.
StreamWriter writer = new StreamWriter("SomeFile.txt");
// Rewrite the entire value of s to the file
writer.Write(str);

You can also just add a line to the end of the file as follows:

string str = "Some text";
// Hook a write to the text file.
StreamWriter writer = new StreamWriter("SomeFile.txt");
// Rewrite the entire value of s to the file
writer.WriteLine(str);

Example for learning

An example of these in a little project file made with MonoDevelop.

using System;
using System.IO;

namespace FileAccess
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			string FileName="TestFile.txt";

			// Open the file into a StreamReader
			StreamReader file = File.OpenText(FileName);
			// Read the file into a string
			string s = file.ReadToEnd();
			// Close the file so it can be accessed again.
			file.Close();

			// Add a line to the text
			s  += "A new line.\n";

			// Hook a write to the text file.
			StreamWriter writer = new StreamWriter(FileName);
			// Rewrite the entire value of s to the file
			writer.Write(s);

			// Add a single line
			writer.WriteLine("Add a single line.");

			// Close the writer
			writer.Close();
		}
	}
}

Well, this should get you started.

C# (Mono) on FreeBSD

Well, if you have read my blog at all, you will realize that I have a developer job writing in C# on Windows, but it is my personal hobby to use FreeBSD.

I am very excited about Mono. I love the C# language. I also love FreeBSD.

I am going to go ahead and say something bold. Few people now realize this yet, but the ability to code in C# on open source platforms is going to be the single most important feature in the coming years. It will eventually be a standard library that will exist or be one of the first items installed on every system.

For more information:

http://www.mono-project.com/Mono:FreeBSD
Packaging for Mono and related applications on FreeBSD (http://www.freebsd.org) is handled by the BSD# Project. The purpose of this project is to maintain the existing Mono/C# ports in the FreeBSD ports tree, port new applications, and work on resolving FreeBSD specific issues with Mono. BSD# is entirely user supported and is not an official FreeBSD or Mono project.

For Licensing information:

http://www.mono-project.com/Licensing

Installing Mono

Mono is a port and as always a port is easy to install on FreeBSD.

Note: The version of mono in ports is not necessarily the latest and greated. I recommend that you install the latest version of mono. See this article.
Installing the latest version of Mono on FreeBSD or How to install and use portshaker?

#
#
cd /usr/ports/lang/mono
make BATCH=yes install

Compiling Hello World in Mono

The mono compiler is gmcs. It is simple to compile C# code.

  1. Create a new file called hw.cs. C# class files end in .cs.
  2. Add this text to the file:
    using System;
    
    namespace HelloWorld
    {
         class HelloWorld
        {
            static void Main(string[] args)
            {
                System.Console.WriteLine("Hello World");
            }
        }
    }
    
  3. Save the file.
  4. Compile the code to create an hw.exe program.
    # gmcs hw.cs

Running a Mono Program

Mono programs must be run using the “mono” command.

# mono hw.exe
Hello World

A Mono IDE: MonoDevelop

There is an IDE for Mono called MonoDevelop. MonoDevelop is a port and as always a port is easy to install on FreeBSD.

#
#
cd /usr/ports/devel/monodevelop
make BATCH=yes install

The Mono Develop port integrated with KDE to add itself to the KDE menu under Applications | Development | MonoDevelop. So you can run it from there.

This IDE allows you to create C# solutions. It is possible to run compile them on FreeBSD and run them on Windows, or compile them on Windows and run them on FreeBSD.

Is It Really Cross Platform

C# and Mono are supposed to be cross platform. So I can write it in Windows using Visual Studio or I can write in FreeBSD using Mono Develop and either way it should run on both Windows and FreeBSD and any other platform that supports mono.

So here are the results of my quick tests:

Test 1 – Does the Hello World app run in Windows.

Yes. I copied the file to a Windows 7 64 bit box and ran it. It worked.

Test 2 – Does a GTK# 2.0 Project run in Windows

No. I created a GTK# 2.0 project on FreeBSD in Mono Develop, and didn’t add anything to it, I just compiled it. I copied the file to windows and ran it. However, it crashed.

Supposedly you have to install the GTK# for .NET on the windows box, but it still didn’t work.

Test 3 – Does a Windows Form Application compiled in Visual Studio 2010 in Window 7 run on FreeBSD

Not at first. I created a basic Windows Form application, and didn’t add anything to it, I just compiled it. I copied it to FreeBSD and ran it. It crashed. However, by default .NET 4.0 is used.

Yes, if compiled with .NET 3.5 or earlier. I changed the project to use .NET 3.5 and tried again. It ran flawlessly.

Test 4 – Does a Windows Presentation Foundation project compiled in Visual Studio 2010 in Window 7 run on FreeBSD

No. There is PresentationFramework assembly so the application crashes immediately. I tried multiple .NET versions.

Note: I didn’t really test much more than the basics. I just created new projects, left them as is and tried them. It would be interesting to see a more fully developed application tested and working on both platform and to know what issues were encountered in doing this.

No WPF

Unfortunately there is no WPF and no plans for it. Of course, WPF stand for Windows Presentation Foundation, and so the who “Windows” part of that might need to be changed to something like XPF, Xorg Presentation foundation.

However since there is Moonlight, which is to Silverlight as Mono is to C# and .NET, and Silverlight is a subset of WPF, I have to assume that WPF will arrive in mono eventually, even if it is by way of Moonlight first.

How to upload a file to an FTP server using C#?

C# (Mono) on FreeBSD

Ok, so today I needed to FTP a file.  It took me some time and research but I have a function that will upload a file to an FTP server.

I found a lot of examples that were very complex, and rightfully so as they have a lot of error and exception handling. However, this complexity makes it difficult to learn.

So this is a non-complex version. It follows some basic steps:

  1. Get the local file name: C:\Users\Rhyous\Desktop\File1.zip
  2. Open a request using the full destination ftp path: Ftp://Ftp.Server.tld/Path/File1.zip
  3. Configure the connection request
  4. Create a stream from the file
  5. Read the file into the a local stream
  6. Close the local stream
  7. Create a stream to the FTP server
  8. Write the local stream to the FTP stream
  9. Close the stream to the FTP server
using System;
using System.IO;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
			string ftplocation = "ftp://ftp.server.tld/path";
			string file = @"C:\Users\Rhyous\Desktop\File1.zip" // Or on FreeBSD: "/usr/home/jared/test2.txt";
			string user = "Anonymous";
			string password = "AnyPasswd!";
            UploadToFTP(ftplocation, file, user, password);
        }

        static void UploadToFTP(String inFTPServerAndPath, String inFullPathToLocalFile, String inUsername, String inPassword)
        {
            // Get the local file name: C:\Users\Rhyous\Desktop\File1.zip
            // and get just the filename: File1.zip. This is so we can add it
            // to the full URI.
            String filename = Path.GetFileName(inFullPathToLocalFile);

            // Open a request using the full URI, c/file.ext
            FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(inFTPServerAndPath + "/" + filename);

            // Configure the connection request
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.Credentials = new NetworkCredential(inUsername, inPassword);
            request.UsePassive = true;
            request.UseBinary = true;
            request.KeepAlive = false;

            // Create a stream from the file
            FileStream stream = File.OpenRead(inFullPathToLocalFile);
            byte[] buffer = new byte[stream.Length];

            // Read the file into the a local stream
            stream.Read(buffer, 0, buffer.Length);

            // Close the local stream
            stream.Close();

            // Create a stream to the FTP server
            Stream reqStream = request.GetRequestStream();

            // Write the local stream to the FTP stream
            // 2 bytes at a time
            int offset = 0;
            int chunk = (buffer.Length > 2048) ? 2048 : buffer.Length;
            while (offset < buffer.Length)
            {
                reqStream.Write(buffer, offset, chunk);
                offset += chunk;
                chunk = (buffer.Length - offset < chunk) ? (buffer.Length - offset) : chunk;
            }
            // Close the stream to the FTP server
            reqStream.Close();
        }
    }
}

This works well for most files.

One problem is that this code reads the entire local file into memory, which might not be a good idea for a file that is very large (multiple gigabytes). It would be better to read the local file in bits. I upload in bits so this would not be hard to read a little bit, upload it, read a little bit more, upload it, etc…

Resources:
http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx
http://msdn.microsoft.com/en-us/library/system.io.stream.aspx
http://www.vcskicks.com/csharp_ftp_upload.php