Multiline lambda expressions Syntax in VB 10 (VS 2010)

Share on Facebook

I did not find much documentation or samples on the web about the newly introduced VB.NET 10 multiline lambda expressions so I decided to document this little nugget to save anybody the time. The C# language has supported multiline lambdas pre VS 2010, but VB users did not have the feature until the 2010 release.

There are a few places where I found discussions on the feature online and these include: vbcity and StackOverflow and also at Channel 9. Besides the multiline statements, there is also now support for subprocedures (sub) or (void functions if your roots are deep in c).

Alright, so say, you want to wire up dependency injection with structureMap for your mvc application: StructureMap uses a recommended BootStrapper approach which helps further decouple its wiring into your global.asax application start code. Most of the samples available for this online are in c# and if you try rewritting in VB you might find the compiler complaining about the lambdas used in your custom registry class below. Most of the c# samples look like below (the sample code is from Elijah Manor's blog):

public static class Bootstrapper 
{
    public static void ConfigureStructureMap()
    {
        ObjectFactory.Initialize(x => x.AddRegistry(new MyApplicationRegistry()));            
    }
}

public class MyApplicationRegistry : Registry
{
    public MyApplicationRegistry()
    {
        Scan(assemblyScanner =>
        {
            assemblyScanner.TheCallingAssembly();
            assemblyScanner.WithDefaultConventions();
        });
    }
}

For the vb 10 version of the above code, you will have to use the new void function lambda and the multiline feature as below:

Public Shared Sub ConfigureStructureMap()
   ObjectFactory.Initialize(Sub(x) x.AddRegistry(New MyApplicationRegistry()))
End Sub

Public Class MyApplicationRegistry
   Inherits Registry

        
    Public Sub New()
            
	Scan(Sub(assemblyScanner)
                     
		assemblyScanner.TheCallingAssembly()
                     
		assemblyScanner.WithDefaultConventions()
                 
   	End Sub)
        
    End Sub
    
End Class

Sure you could use a converter, but its worth documenting it here, just in case the converter is unavailable. Hope this helps you.


Mocking IPrincipal User with MvcContrib.TestHelper

Share on Facebook

Recently I needed to mock an IPrincipal implementation while testing an Mvc web app I was writting. I eventually managed to piece together the scattered bits of information required to achieve this. However I felt the information was not presented in any coherent manner while searching so If you need to do similar, here you go. I believe the code is reasonably self documenting. I am using the mvccontrib testhelper with Rhino Mocks.

namespace Commerce.MvcWeb.Tests.Controllers

{

    [TestClass]

    public class BasketControllerTests : TestBase

    {

        private IBasketRepository mockBasketRepo;

        private BasketController ControllerUnderTest;

        [TestInitialize]

        public void ChildSetUp()

        {           

            mockBasketRepo = MockRepository.GenerateMock();

            mockBasketRepo.Stub(x => x.Config).Return(mockConfig);

        }

        [TestMethod]

        public void Test_Basket_Index_Returns_Model_To_Index_View()

        {

  //Arrange                              

            List items = new List();

            for (int i = 0; i < 5; i++) { items.Add(new BasketItem { ProductID = i, ProductName = "product" + i.ToString(), Quantity = i,  PricePaid = (Decimal)i, LineTotal = (Decimal)0.175 }); }

            Basket basket = new Basket { Items = items, UserName = "Administrator", OrderTotal = 200, SubTotalAmount = 150 }; 

            mockBasketRepo.Expect(x => x.GetBasket("Administrator")).Return(basket);

            //Act

            ControllerUnderTest = new BasketController(mockBasketRepo);

            builder.InitializeController(ControllerUnderTest);                        

            ViewResult result = ControllerUnderTest.Index()  as ViewResult;

            //Assert

            ControllerUnderTest.Index().AssertViewRendered();            

        }

    }

}

namespace Commerce.MvcWeb.Tests.Controllers

{

    [TestClass]

    public class TestBase

    {

        protected IConfiguration mockConfig;

        protected TestControllerBuilder builder;

        [TestInitialize]

        public virtual void SetUp()

        {

            builder = new TestControllerBuilder();

            //Initialise fake Configuration for testing

            mockConfig = MockRepository.GenerateMock();

            mockConfig.Stub(x => x.SiteTitle).Return("Welcome to Test Site");

            mockConfig.Stub(x => x.SiteDescription).Return("Description of Test Site");

            mockConfig.Stub(x => x.SiteKeywords).Return("Description,of,Test,Site");

            //Initialise fake HttpContext on Test Builder Object for Testing 

            System.Web.HttpCookieCollection cookies = new System.Web.HttpCookieCollection();

            cookies.Add(new System.Web.HttpCookie("ShopperID", "Administrator"));

            builder.HttpContext.Request.Expect(x => x.Cookies).Return(cookies);

            FakeIdentity fakeID = new FakeIdentity("Administrator");

            FakePrincipal fakeUser = new FakePrincipal(fakeID, null);

            builder.HttpContext.User = fakeUser;

            Uri Url = new Uri(@"http://localhost/xxx");

            builder.HttpContext.Request.Expect(x => x.Url).Return(Url);

            //builder.HttpContext.Request.Expect(x => x.ServerVariables).Return(new NameValueCollection());

        }

    }

}


Google sitemap handler/generator for vevocart free

Share on Facebook

Vevocart has a free version which enables a merchant to setup a simple online shop with very little initial capital. However, there are a lot of features on vevocart which are only available with the premium version. One such feature is Search Engine Optimisation or SEO for short.

I needed to provide a dynamically generated google sitemap compatible xml feed for use with the google webmaster tools, so I coded one up in VB.Net. If you need it you may download it by clicking the link below.

using System;
using System.Web;
using System.Xml;
using System.Text;
using System.Configuration;
using System.Data.OleDb;

public class sitemapclass : IHttpHandler
{

public void ProcessRequest(HttpContext context)
   {
    String changefrequency = "weekly"; // always,  hourly,  daily,  weekly,  monthly,  yearly, never
    using (System.IO.TextWriter textWriter=new System.IO.StreamWriter(context.Response.OutputStream,System.Text.Encoding.UTF8))  {
    XmlTextWriter writer = new XmlTextWriter(textWriter);
    writer.Formatting = Formatting.Indented;
    writer.WriteStartDocument();
    writer.WriteStartElement("urlset");
    writer.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
    
    // Add Domain
    writer.WriteStartElement("url");
    writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/'));
    writer.WriteElementString("changefreq",  changefrequency);
    writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
    writer.WriteEndElement();
    // Add Home Page
    writer.WriteStartElement("url");
    writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/') + "/Default.aspx");
    writer.WriteElementString("changefreq",  changefrequency);
    writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
    writer.WriteEndElement();
	
	// About Us Page
    writer.WriteStartElement("url");
    writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/') + "/AboutUs.aspx");
    writer.WriteElementString("changefreq",  changefrequency);
    writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
    writer.WriteEndElement();
	
	// Contact Us Page
	writer.WriteStartElement("url");
    writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/') + "/ContactUs.aspx");
    writer.WriteElementString("changefreq",  changefrequency);
    writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
    writer.WriteEndElement();
	
	// Policy Page
	writer.WriteStartElement("url");
    writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/') + "/Policy.aspx");
    writer.WriteElementString("changefreq",  changefrequency);
    writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
    writer.WriteEndElement();

    using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + context.Server.MapPath(ConfigurationManager.ConnectionStrings["MainConnection"].ConnectionString))) 
    {
        using (OleDbCommand productsCommand = new OleDbCommand("SELECT productID, UrlName from Product", conn))
        {
            conn.Open();
            OleDbDataReader productReader = productsCommand.ExecuteReader();
            while (productReader.Read())
            {
			// products
                int productid = int.Parse(productReader["productID"].ToString());
				string urlname = productReader["UrlName"].ToString();
                 writer.WriteStartElement("url");
                 writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/') + Vevo.UrlManager.GetProductUrl( productid, urlname ).Replace(@"~",@""));
                 writer.WriteElementString("changefreq", changefrequency);
                 writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
                 writer.WriteEndElement();
            }
        }
				
		using (OleDbCommand categoriesCommand = new OleDbCommand("SELECT CategoryID,UrlName from Category", conn))
        {
            OleDbDataReader categoryReader = categoriesCommand.ExecuteReader();
            while (categoryReader.Read())
            {
			// categories
                int categoryid = int.Parse(categoryReader["CategoryID"].ToString());
				string urlname = categoryReader["UrlName"].ToString();
                writer.WriteStartElement("url");
                writer.WriteElementString("loc", "http://" + context.Request.ServerVariables["SERVER_NAME"] + context.Request.ApplicationPath.TrimEnd('/') + Vevo.UrlManager.GetCategoryUrl( categoryid, urlname ).Replace(@"~",@""));
                writer.WriteElementString("changefreq", changefrequency);
                writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
                writer.WriteEndElement();
            }
        }			
    }
    writer.WriteEndDocument();
    }
}

public bool IsReusable
{
    get
    {
        return false;
    }
}

}

 

Please post any bugs or feedbacks. As usual the download is without any warranty what so ever.

HTH

 

sitemap.ashx (5.37 kb)


ODBC Access to Sage Line 50 from VB.Net

Share on Facebook

So I had a few challenges accessing Sage Data via the Sage supplied ODBC Driver for Sage Line 50 vX from Vb.Net code.

The specific error message is:

System.Data.Odbc.OdbcException: ERROR [08001] Cannot find all files in data path ERROR [01000] The driver returned invalid (or failed to return) SQL_DRIVER_ODBC_VER: 2.00 ERROR [IM006] [Microsoft][ODBC Driver Manager] Driver's SQLSetConnectAttr failed ERROR [01000] [Microsoft][ODBC Driver Manager] The driver doesn't support the version of ODBC behavior that the application requested (see SQLSetEnvAttr).

There were a few suggestions from forums that this had to do with Code Access Security permissions on the .Net platform.Some people suggested elevating trust level from medium to Full ie. <trust level="Full" />, others suggested impersonation with a user who has access to the ODBC data store <identity impersonate="true" userName="myname" password="mypassword" />

Since I was on a development box and running the app in Visual studio, the appDomain already runs in full trust, so the full trust suggestion did not work. Secondly, I tried the identity impersonation option but it did not fix the problem either. I found out the reason being, my ODBC DSN had a path mapped to a network share, and I had no permission as per the impersonating identity to that shared drive.

So what is the simple solution?, for dev purposes, I changed the ODBC store path in Control panel\Administrative Tools\Data Sources\System DSN\SageLine50v11 to point to a local drive, (By default this would be: C:\Progra~1\Sage\Accounts\ACCDATA) and it took care of the error completely.

When I deploy to the server, the ODBC store on the server will have a path pointing to a local drive. This way I don't have to mess up my permission sets on any system.

So, the ODBC driver supplied by sage works with .Net, remember  though that this driver is readonly and does not write back data to the Sage proprietory database. If you need sample connection strings, try the following:

connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;DSN=SageLine50v11;Driver={Sage Line 50v11};uid=USERNAME;pwd=PASSWORD;"

connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;DSN=SageLine50v11;uid=USERNAME;pwd=PASSWORD;"

connectionString = "DSN=SageLine50v11;uid=USERNAME;pwd=PASSWORD;"

All three connection strings above worked for me. REMEMBER to replace USERNAME with your user name and PASSWORD with your password.

 

 

HTH

 


Paypal buttons extension for blogengine

Share on Facebook

Whereas wordpress has plugins for stuff like paypal donate and buy now buttons in abundance,

Blogengine is far behind the competition for stuff like that. I know people might have developed such extensions, but are probably not yet willing to share them with fellow blogengine users. I thought I will change that so I am releasing my paypal buttons for blogengine extension for you all to use.

Technically, the extensions are simple and just wrap the paypal html for the buttons in .Net code and provide an easy setup via the extensions manager in blogengine.

EXAMPLE:

The donate button on this site is an example usage of the donate button extension.

USAGE SYNTAX:

 

DOWNLOAD:

You may download the extensions below. To install the extensions, simply copy the downloaded file into your /App_Code/Extensions folder of your blogengine site root folder.

 

PaypalAddToBasketButtons.cs (6.72 kb)

PaypalBuyNowButtons.cs (6.13 kb)

PaypalDonateButton.cs (5.49 kb)

Please post comments if you have any bugs or modifications or enhancements.

Cheers!

NB: As usual the software is provided free of charge and use at your own risk. If you have any questions, I will do my best to provide the answers in my free time, if I ever really have any!


Enhanced FlickrPicture Extension for BlogEngine

Share on Facebook

OK, well maybe "enhanced" is too far fetched. If you've been using blogengine and loving the system like I do, then chances are you might have come across this wonderful extension which allows you to easily use your flickr hosted pictures and images within your posts.

The only tiny downside I had with the original extension was that, it did not provide any way of controlling the hosted image size on the fly via the extension itself. In other words, you have to upload multiple sizes to flickr to display the various sizes in a post. Which is not how developers like to do things. You will typically prefer to upload one image and resize it on the fly. OK, well, enough of the blah-blah-blah.

Enhanced flickrpicture extension with size=square : Code [--flickr:3662228891-square] (exc --)

 

pine-forest

 

Enhanced flickrpicture extension with size=small : Code [--flickr:3662228891-small] (exc --)

 

pine-forest

 

Default size flickrpicture usage : Code [--flickr:3662228891] (exc --)

 

pine-forest

 

So I looked a bit closer into flickr sizes (Flickr creates multiple sizes of uploaded images and saves them on their servers.) and added code to the original flickrpicture extension to arrive at this enhanced version which behaves exactly as the original except it now has an optional parameter to take care of the size. By default, it will display the flickr maintained medium size (Or the default size option specified in Extension Manager), But if a size parameter is specified, then it will use that instance size instead.

The syntax is of the form: [--flickr:pictureID] or [--flickr:pictureID-size] without the double dashes (--)

where size is a member of the set (square,thumbnail,small,medium,large) and is a close mapping to the flickr sizes set.

Additionally, I have added an extra setting in the Extensions editor which allows you to choose whether to link back to flickr or not.

When set to true, the image is linked back to the flickr hosted page of the image. When set to flase, the image itself is not linked. You are then able to wrap a link around the extension.

You may download the extension from here:FlickrPicture.zip (1.78 kb)

As usual, unzip the file and copy flickrpicture.cs to your blogengine extensions folder (/App_Code/Extensions).

I have left the name of the extension and developer as Matthew Rygiel. All credit goes to him for creating such a wonderful extension in the first place.

Please post comments and feedback below.

 

 


S3 Slider Demo

Share on Facebook

If you are viewing this post in the post list (or home page), you will not see the animation. Click the title of the post to be taken to the actual page where you will see the animation.

JQuery S3Slider Plugin Demo

  • 1 Alone by the sea
    cloudy evenning by the sea
  • 2 Clouds
    The Clouds are gathering, lower layers and higher layers
  • 3 Country Sunset
    Country sunset sky with clouds
  • 4 Sunset by the Mountains
    Sunset against the backdrop of an arc of mountains
  • 5 A Awarm Sunset
    Good place to be when you want to ponder and retreat
  •  

 

Recently I stumbled on the S3Slider JQuery plugin and liked the look and feel of the transition animations and the behaviour of the overlayed text.

So I set out to try an implementation of the S3Slider slide show in blogengine. The good news is that there is a very good JQuery Extension for blogengine by John Callaway of http://www.internetblu.com.

This extension in my opinion provided a very good approach to deploying jQuery on BlogEngine and had done 99% of the job, In the sense that once installed you are able to load jQuery plus any other jQuery plugin on Posts and Pages.

The 1% involved calling JQuery functions or Plugin functions after the DOM has been loaded. In keeping with the BlogEngine tradition of doing add-on tasks via Extensions and widgets rather than modifying the core .aspx files, I decided to write two Extensions to help solve the 1% left to achieve the objective.

 

EXTENSION 1: Add Header File

The Add Header File Extension does what it says, It allows you to load a .css style sheet or a javascript file with full or partial path into a post or page.

The syntax is of the form:
[--AddHeaderFile:filename.css|filename.js;SCRIPTID]. Without the double dashes (--). The SCRIPTID parameter is used to prevent duplication of the script if there

is an attempt to load the same script again onto the page. 

 

EXTENSION 2: Add Script

The add script extension allows you to call JQuery and plugin functions from within the post or page. The Syntax is of the form:

[--AddScript:javascriptcode]

Without the double dashes (--)

 

With the above 2 Extensions and the JQuery Extension for blog Engine, I was able to achieve the S3Slider plugin effect in BlogEngine with the Code segment below:

 

[--AddHeaderFile:http://www.levitical.org/themes/nonzero/s3sliderMain.css;SLIDERCSS]
[--AddScript:$j=jQuery.noConflict();$j(document).ready(function(){$j('#slider').s3Slider({timeOut: 3000}); });]

The two dashes (--) are obviously not included in the code. The remainder is just Html markup in the form of an unordered list (ul) in a container div with id=slider. This container is the object we initialise the s3Slider script on in the AddScript Extension code above. The html markup code is listed below:
  • 1 Alone by the sea
    cloudy evenning by the sea
  • 2 Clouds
    The Clouds are gathering, lower layers and higher layers
  • 3 Country Sunset
    Country sunset sky with clouds
  • 4 Sunset by the Mountains
    Sunset against the backdrop of an arc of mountains
  • 5 A Awarm Sunset
    Good place to be when you want to ponder and retreat
  •  


Hope you find it imformative.

You may download the two Extensions from the archive link below. Upon extracting the files, drop the two extension files,
AddHeaderFile.cs and InjectJsCsriptToHeader.cs into the App_Code/Extensions folder and you are ready to roll. Please post any bugs, comments or feedback.

 

 


Free Video and Audio Merging tools

Share on Facebook

Recently I developed a site which used the JW Player to play some video content hosted by a free video hosting service provider. I hit a brick wall when it was necessary to play an intro clip to each of the movies. The challenge is that although the JW player plays many a variety of xml playlist formats (asx,rss,atom,xspf,smil etc), It does not provide any mechanism for playing a specific intro clip to all entries in the playlist.

I tried to find a solution by going down the line of nested playlists, where I could create a sub playlist if you like, with the intro clip as first entry for each track in the main playlist, but had no joy. Although a few people said the JW Player could play nested xspf playlists, I just didn't have any luck with it.

 

 

Free Video Joiner in Action

Finally, I had to go down the route of finding easy to use tools to merge (or prepend as it were) the intro video to the main entries in the playlist before uploading to the hosting provider. At least that works OK and the problem is solved. You might think Windows Movie Maker will be a good candidate software for the task, but I quickly dropped it out of the list because, WMM always re-encoded the final movie into a totally new movie and in the process results in a loss of quality. There was a very helpful tool called free video joiner I used to easily merge the videos, you may download it from the link below:

Download Free Video Joiner

However, as good and easy to use as the above tool is, it does not support merging flvs. Flvs are however the preferred format for video hosting and streaming online, since 95% of all machines and browsers are flash ready. So if you need to merge flvs, are you stuck ? No. You are still in luck (Not like I believe in luck though, but that's a different subject for another day). As it happens, there is Andy's flv Joiner for the task of simply merging multiple flv files into one.

 

 

You may Download Andy's flv joiner from here.

I needed to do similar with mp3 audios where I needed to prepend an intro and outro mp3 to the beginning and end respectively of the main clip, the tool that came in handy for the mp3 merger is Free Mp3/WMA/Ogg Converter. You may download the tool from the link below:

 

 

Download Free MP3/WMA/OGG Converter

If you want a bit more control at editing and merging mp3 files and want an open source alternative to industry tools like Steinberg's wavelab, then you could try audacity, by downloading it from here.

 

If you have to rip DVD video from a Disk to your hard drive or change video enconding from say WMV to FLV, then you might want to try eRightSoft's SUPER

Download eRightSoft's Super from here

Hope this helps.

 


asp.net ajax image zoom implementation part 2

Share on Facebook

A while ago, I wrote a blog post on how to implement an asp.net ajax zooming system. If you haven't read that post as yet, you may read it here. The approach was at the time very promising with the release of asp.net AJAX, but at this point in time, there are far more superior technologies such as silverlight and WPF for achieving rich content in the browser and also powerful javascript libraries such as jQuery,MooTools and scriptaculous. However, I did promise in that article to post actual implementation code once I got to a point in the project which was a basic implementation of the concepts. I have been busy for a long time and hardly found time to finish this up. There have been quite a few people reading the post and expressing disappointment at the end due to the absence of a code sample, so in keeping with the promise, I have whipped up some code to demonstrate the concepts enumerated in that post.

The fig below shows the demo in action:

You may preview and engage a live demo from here.

The resizing of the image on the fly is accomplished through the ImageResize class. The main method of the ImageResize class which does the heavy lifting is GetThumbNail and is listed below:

Public Overridable Overloads Function GetThumbnail() As System.Drawing.Image
            ' check  whether a new image is required
            Dim recalc As Boolean = False
            Dim new_width As Double = Width
            Dim new_height As Double = Height

            ' Check if there is a cached source image available.
            ' check if imagepath was defined if not use the image in the Image member
            If Not CheckIsSameSourceImage(_cachedImage) Then
                If _imagePath.Length > 0 Then
                    ' Load via stream rather than Image.FromFile to release the file
                    If Not IsNothing(_sourceImage) Then
                        _sourceImage.Dispose()
                    End If
                    ' To ensure the handle gets closed when the object goes out of scope
                    ' wrap the filestream in a "using" directive
                    Using _stream As Stream = New FileStream(_imagePath, FileMode.Open, FileAccess.Read)
                        _sourceImage = System.Drawing.Image.FromStream(_stream)
                    End Using
                    recalc = True
                End If
            End If

            'Check whether the required destination image properties have changed
            If Not CheckIsSameDestinationImage(_cachedImage) Then
                ' Yes, so we need to recalculate.
                ' If you opted to specify width and height as percentages of the original
                ' image's width and height, compute these now
                If (UsePercentages) Then
                    If (Width <> 0) Then
                        new_width = Double.Parse(_sourceImage.Width) * Width / 100
                        If (PreserveAspectRatio) Then
                            new_height = new_width * _sourceImage.Height / Double.Parse(_sourceImage.Width)
                        End If
                    End If

                    If (Height <> 0) Then
                        new_height = Double.Parse(_sourceImage.Height) * Height / 100
                        If (PreserveAspectRatio) Then
                            new_width = new_height * _sourceImage.Width / Double.Parse(_sourceImage.Height)
                        End If
                    End If
                Else
                    ' If you specified an aspect ratio and absolute width or height, then calculate this 
                    ' now; if you accidentally specified both a width and height, ignore the 
                    ' PreserveAspectRatio flag
                    If (PreserveAspectRatio) Then
                        If (Width <> 0 And Height = 0) Then
                            new_height = (Width / Double.Parse(_sourceImage.Width)) * _sourceImage.Height
                        ElseIf (Height <> 0 And Width = 0) Then
                            new_width = (Height / (Double.Parse(_sourceImage.Height)) * _sourceImage.Width)
                        End If
                    End If
                End If
                recalc = True
            End If

            If (recalc) Then
                ' Calculate the new image
                If Not IsNothing(_destinationImage) Then
                    _destinationImage.Dispose()
                    _graphics.Dispose()
                End If

                'Create a square bitmap as canvas
                Dim _bitmap As System.Drawing.Bitmap
                If new_width > new_height Then
                    _bitmap = New Bitmap(Double.Parse(new_width), Double.Parse(new_width), PixelFormatType)
                Else : _bitmap = New Bitmap(Double.Parse(new_height), Double.Parse(new_height), PixelFormatType)
                End If

                'Initialise graphics with In-Memory bitmap
                _graphics = Graphics.FromImage(_bitmap)

                'If there is a background Image setting, use it for the background
                If Not String.IsNullOrEmpty(_backgroundImageUrl) Then
                    Dim backgroundimage As System.Drawing.Bitmap
                    Using _stream As Stream = New FileStream(HttpContext.Current.Server.MapPath(_backgroundImageUrl), FileMode.Open, FileAccess.Read)
                        backgroundimage = System.Drawing.Bitmap.FromStream(_stream)
                    End Using
                    If Not IsNothing(backgroundimage) Then
                        _graphics.DrawImage(backgroundimage, 0, 0, _bitmap.Width, _bitmap.Height)
                    End If
                Else
                    'Else Set graphics canvas color to the set CanvasColor
                    _graphics.FillRectangle(_canvasColor, 0, 0, _bitmap.Width, _bitmap.Height)
                End If

                'Set various properties for Resizing
                _graphics.InterpolationMode = InterpolationType
                _graphics.SmoothingMode = SmoothingType
                _graphics.CompositingMode = CompositingModeType
                _graphics.CompositingQuality = CompositingQualityType
                Dim NewHeight As Integer = CType(new_height, Integer)
                Dim NewWidth As Integer = CType(new_width, Integer)

                'If AutoPositioning then center image vertically or 
                'horizontally depending on which dimension is larger
                'Resize proportionately
                If AutoPositioning Then
                    If new_width > new_height Then
                        _graphics.DrawImage(_sourceImage, PositionX, CType((NewWidth - NewHeight) / 2, Integer), NewWidth, NewHeight)
                    Else : _graphics.DrawImage(_sourceImage, CType((NewHeight - NewWidth) / 2, Integer), PositionY, NewWidth, NewHeight)
                    End If
                Else ' Not AutoPositioning
                    'Dim srcRect As New Rectangle(PositionX, PositionY, NewWidth, NewHeight)
                    'Dim destRect As New Rectangle(PositionX, PositionY, 300, 300)
                    '_graphics.DrawImage(_sourceImage, destRect, srcRect, GraphicsUnit.Pixel)
                    _graphics.RenderingOrigin() = New Point(NewWidth / 2, NewHeight / 2)
                    _graphics.DrawImage(_sourceImage, PositionX, PositionY, NewWidth, NewHeight)
                End If

                'Apply watermarks
                If Not String.IsNullOrEmpty(_watermarkImageUrl) Then
                    Dim watermarkimage As Bitmap
                    Using _stream As Stream = New FileStream(HttpContext.Current.Server.MapPath(_watermarkImageUrl), FileMode.Open, FileAccess.Read)
                        watermarkimage = System.Drawing.Image.FromStream(_stream)
                    End Using
                    'Draw at the top left corner
                    If NewWidth > NewHeight Then
                        _graphics.DrawImage(watermarkimage, 0, 0) 'NewWidth - 15)
                    Else : _graphics.DrawImage(watermarkimage, 0, 0) 'NewHeight - 15)
                    End If
                End If


                If Not String.IsNullOrEmpty(_watermarkText) Then
                    'Draw at the top left corner
                    If NewWidth > NewHeight Then
                        _graphics.DrawString(_watermarkText, _watermarkFont, _watermarkBrush, 0, 0) 'NewWidth - 15)
                    Else : _graphics.DrawString(_watermarkText, _watermarkFont, _watermarkBrush, 0, 0) 'NewHeight - 15)
                    End If
                End If

                _destinationImage = _bitmap
                ' Put the image in the Cache
                '_cachedImage = CType(Me.MemberwiseClone(), ImageResize)
            End If
            Return _destinationImage
        End Function

 

The code for the generic handler class (ImageZoomHandler.ashx) which feeds the asp.net image control's ImageUrl property is listed below:

Imports System.IO
Imports System
Imports System.Web

Public Class ImageSizeHandler : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        
        'Read in the image filename to create a thumbnail of
        Dim imageUrl As String = context.Request.QueryString("img")
        If imageUrl.StartsWith("../") Then
            imageUrl = imageUrl.Replace("../", "")
        End If
    
        'Read in the dimensions
        Dim width As Integer = context.Request.QueryString("w")
        Dim height As Integer = context.Request.QueryString("h")
        Dim xPos As Integer = 0
        Dim yPos As Integer = 0
        If Not String.IsNullOrEmpty(context.Request.QueryString("x")) Then
            xPos = Integer.Parse(context.Request.QueryString("x"))
        End If
        If Not String.IsNullOrEmpty(context.Request.QueryString("y")) Then
            yPos = Integer.Parse(context.Request.QueryString("y"))
        End If                
              
        'create a new instance of the resizer class and set necessary properties
        Dim imgResizer As Commerce.Common.ImageResize = New Commerce.Common.ImageResize
        imgResizer.ImagePath = context.Server.MapPath("~/" + imageUrl)
        
        If width < 400 And height < 400 Then
            imgResizer.Width = width
            imgResizer.Height = height
            imgResizer.PositionX = xPos
            imgResizer.PositionY = yPos
        ElseIf width >= 400 Or height >= 400 Then
            Dim OriginX As Integer = 0
            Dim OriginY As Integer = 0
            If width >= 400 Then
                OriginX = (400 - width) / 2
                OriginY = (400 - height) / 2
            Else
                OriginX = (400 - height) / 2
                OriginY = (400 - height) / 2
            End If
            imgResizer.Width = width
            imgResizer.Height = height
            imgResizer.PositionX = OriginX + xPos
            imgResizer.PositionY = OriginY + yPos
        End If
        
        imgResizer.PreserveAspectRatio = True
        imgResizer.AutoPositioning = False
        imgResizer.UsePercentages = False
        
        'Initialise response stream
        context.Response.Clear()
        context.Response.BufferOutput = True
        context.Response.ContentType = "image/jpeg"
        context.Response.AppendHeader("content-disposition", "filename=ProductImage.jpg")
        
        'create new image and render to Output Stream of Response.
        imgResizer.GetThumbnail().Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)
        context.Response.End()        
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

As you may have realised from the downloaded project, the system is no where near perfect. My objective for posting it here is for someone to pick it up, fine tune it and add some icing on it, so we can all use it sometime in the future.
Please post any comments below.
Cheers!

You may download the visual studio project for the demo as a zip archive by clicking the link below:

ImageZoom.zip (321.98 kb)


Excel VB.Net constants reference

Share on Facebook

I just felt like contributing to the visibility of these constants on the web. If you try to port VBA code from VB 6.0 to the .Net environment using VS 2003/5/8 interop assemblies for Excel, you will quickly find out that the Excel constants (typically with prefix Xl and format Xlxxxxx) no longer have global visibility. Each set of constants have been grouped into a type.

It is a pain sometimes trying to figure out the appropriate type for the constant. Luckily an MSDN page lists all the types. The page is at:

http://msdn.microsoft.com/en-us/library/aa221100(office.11).aspx# 

 

Hope this helps.

 

Cheers! 


About Me

When not scratching my head for solutions to software challenges, I spend my time playing with my little boy - Michael Jnr.

Quotations

"Anger is never without Reason, but seldom with a good One."
Benjamin Franklin

Donate with PayPal - it

Calendar

<<  July 2010  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2005 - 2010

Search