click to return home

  • Home
  • Archive
  • Contact
  • FeedSubscribe
  • Log in

RecentPosts

  • URL Rewriting with Asp.Net Modules, Dynamic TitlesComments: 5Rating: 0 / 0
  • Dynamic Menu using Xml Datasource, Sql Server.Comments: 32Rating: 0 / 0
  • Store and Retrieve an image from Database sql serverComments: 36Rating: 4 / 1
  • Setting up BlogEngine SubdirectoryComments: 7Rating: 5 / 1

Category list

  • RSS feed for Asp.Net ControlsAsp.Net Controls (1)
  • RSS feed for Blog Engine InstallBlog Engine Install (1)
  • RSS feed for C# Asp.NetC# Asp.Net (2)
  • RSS feed for XmlXml (1)

Tag cloud

  • blog
  • blogengine
  • code highlight
  • dynamic
  • engine
  • generic handlers
  • google syntax highlighter
  • httpmodules
  • iis 6
  • iis 7
  • images
  • linq
  • menu
  • rewrite
  • sql server
  • subdirectory
  • thumbnails
  • tiny mce
  • url rewriting
  • web.config
  • xml
  • xml datasource

BlogRoll

  • RSS feed for Mr. Bobby HashMr. Bobby Hash
Download OPML file OPML
Imperial Ages, Free Browser based online gaming. 3 Ages, 4 Races, 111 Military Units. A quest for glory. 3 Dedicated server up 24x7Goto http://s3.imperialages.com/Register.aspx?R=7265

URL Rewriting with Asp.Net Modules, Dynamic Titles

by Nico 28. September 2009 12:21

Url Rewriting, another version.

 

 

So URL Rewriting is a big thing on the web these days. And there are many great blogs about URL rewriting, my favorite is from Scott Gu Tip/Trick Url Rewriting, who by the way has some of the best blogs out there.

Now some of these are not 100% complete, although thorough are missing one key element. Who wants to write an xml file, or a web.config for EVERY product they have? Or who wants to add some extra design time support for your URL Rewriting.

What is Url Rewriting?

URL Rewriting is simple, convert a URL to something else BEFORE IIS processes the full request. In .Net all we need is a HTTP Module that runs before each request comes through. View the example below.

Lets say that we have a product lets call it Johns Classical Music Compilation and in our database this product has a product id of 123456. Well to get to that product we would have a url like

http://www.mycompany.com/products.aspx?productid=123456

Now the above URL may look just fine, but to the regular everyday person this means nothing to us. We dont know what product 123456 is just from the URL. Also Website crawlers such as google, yahoo, msn, etc dont know what you mean by this link. However lets say you had

http://www.mycompany.com/Products/Johns_Classical_Music_Compilation_123456.aspx

Now that is Human readable, contains keywords that the crawlers will pick up and to the normal user means something. Now the best way i have come up with URL rewriting so its completly dynamic is to actually put the product ID in the URL however to the normal user that doesnt really make a difference because the main information is already there.

Lets get some code going!

Ok, to get this started we need to create a Module that processes all requests BEFORE IIS hits it incase we need to rewrite to another URL. Some of this code is directly of Scott Gu's blog above so all the credit must go to him.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Web;
using System.Data;
using System.Configuration;
using System.Reflection;
using System.Text.RegularExpressions;
namespace MySite.Modules
{
    /// 
    /// Summary description for ReWrite
    /// 
    public class ReWrite : System.Web.IHttpModule
    {

        #region Properties
        /// 
        /// Contains Extra Rewriting URL'S. These URLS are for extra items
        /// that are static redirections
        /// 
        private XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath(@"\App_Data\ReWrite.xml"));
        #endregion

        /// 
        /// Init is required from the IHttpModule interface
        /// 
        /// 
        public void Init(System.Web.HttpApplication Appl)
        {
            //make sure to wire up to BeginRequest
            Appl.BeginRequest += new System.EventHandler(Rewrite_BeginRequest);
        }

        /// 
        /// Dispose is required from the IHttpModule interface
        /// 
        public void Dispose()
        {
            //make sure you clean up after yourself
        }

        /// 
        /// To handle the starting of the incoming request
        /// 
        /// 
        /// 
        public void Rewrite_BeginRequest(object sender, System.EventArgs args)
        {
            System.Web.HttpApplication Appl = (System.Web.HttpApplication)sender;
            string RPath = Appl.Request.Path.ToLower();
            // Anytime the Request path contains the sequence /products/
            // load our rewrite object. This parses for the last _ and strips out the file extension
            // converts http://localhost/products/New_Product_123.aspx to product id 123
            if (Appl.Request.Path.ToLower().Contains("/products/"))
            {
                if (RPath.Contains("_"))
                {
                    string ProdID = RPath.Substring(RPath.LastIndexOf("_") + 1);
                    ProdID = ProdID.Substring(0, ProdID.IndexOf(".")).ToUpper();
                    string toPath = string.Format("/Product.aspx?p={0}", ProdID);
                    SendToNewUrl(toPath, Appl);
                }
                else
                    SendToNewUrl("/NoProductFound.aspx", Appl);
            }
            else
            {
                // Linq Commands that parses the XML document to find items listed
                // in our static URL xml File
                RewriteItem[] items = (from r in doc.Descendants("root").Elements("item")
                                       select new RewriteItem
                                       {
                                           ID = r.Attribute("id").Value.ToLower(),
                                           ReWritePath = r.Attribute("rewritepath").Value.ToLower(),
                                           URL = r.Attribute("url").Value.ToLower()
                                       }).ToArray();
                foreach (RewriteItem i in items)
                {
                    if (RPath.ToLower().Contains(i.URL))
                    {
                        SendToNewUrl(i.ReWritePath, Appl);
                        break;
                    }
                }
            }
        }

        /// 
        /// Re-route the request based on the url
        /// 
        /// 
        /// 
        private void SendToNewUrl(string url, System.Web.HttpApplication Appl)
        {
            applyTrailingSlashHack(Appl);
            Appl.Context.RewritePath(url);
        }

        /// 
        /// Clears a hack caused in IIS 7.0 where a user can accidentally get passed a ReWritten URL by adding a trailing
        /// slash.
        /// 
        /// 
        private void applyTrailingSlashHack(HttpApplication httpApp)
        {
            if (httpApp.Request.Url.AbsoluteUri.EndsWith("/") && !httpApp.Request.Url.AbsolutePath.Equals("/"))
            {
                Type requestType = httpApp.Context.Request.GetType();
                object clientFilePath = requestType.InvokeMember("ClientFilePath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty, null, httpApp.Context.Request, null);
                string virtualPathString = (string)clientFilePath.GetType().InvokeMember("_virtualPath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, null, clientFilePath, null);
                clientFilePath.GetType().InvokeMember("_virtualPath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, clientFilePath, new object[] { virtualPathString });
                requestType.InvokeMember("_clientFilePath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, HttpContext.Current.Request, new object[] { clientFilePath });
                object clientBaseDir = requestType.InvokeMember("ClientBaseDir", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty, null, httpApp.Context.Request, null);
                clientBaseDir.GetType().InvokeMember("_virtualPath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, clientBaseDir, new object[] { virtualPathString });
                requestType.InvokeMember("_clientBaseDir", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, HttpContext.Current.Request, new object[] { clientBaseDir });
            }
        }

        /// 
        /// Returns a RewriteItem object of the item queried by id. For a full
        /// list of items open /App_Data/rewrite.mxl
        /// 
        /// 
        /// 
        public RewriteItem GetItemByID(string ID)
        {
            var item = doc.Descendants("root").Elements("item").SingleOrDefault(x => x.Attribute("id").Value.ToLower() == ID);
            RewriteItem _ritem = new RewriteItem();
            if (item == null)
            {
                _ritem.ID = "-1";
                return _ritem;
            }
            _ritem.ID = item.Attribute("id").Value;
            _ritem.ReWritePath = item.Attribute("rewritepath").Value;
            _ritem.URL = item.Attribute("url").Value;
            return _ritem;
        }

        /// 
        /// RewriteItem Object, contains the XML record set.
        /// 
        public class RewriteItem
        {
            public string ID { get; set; }
            public string ReWritePath { get; set; }
            public string URL { get; set; }
        }
    }
}

 

Now i usually comment my Class files so I will leave the explanation to the code. Next we need another file. As we have some static re-written URL's in a file located at \App_Data\Rewrite.xml so i have provided a sample

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <!-- Insert 1 line per rewrite url-->
  <item id="home" rewritepath="/Default.aspx" url="/Home.aspx" />
 </root>

What does the above let us do? Well now we have an XML that contains extra static data to be URL rewritten. Now in our class file we can parse this file and handle any redirections that are within it. Also you can use the data from this file in our class method called GetItemByID(string ID) returning a type of ReWriteItem containing our 3 attributes.

The last step is simply telling our webserver to use our Module when processing requests. That can be done by adding a simple line to our web.config as below within the httpModules tag.

<httpModules>
			<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="ReWrite" type="MySite.Modules.ReWrite"/>
		</httpModules>


I know this is a very quick overview however if you have questions please do contact me.

Thanks for reading!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: url rewriting, rewrite, httpmodules, xml, linq, web.config

E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (5) | Post RSSRSS comment feed

Dynamic Menu using Xml Datasource, Sql Server.

by Nico 20. March 2009 04:09

I have been looking for a good resource to answer the question of, how can i create a menu that is dynamic from sql server using the Asp:Menu control. With all the frustration i came up with my own and thought i would share it with all of you.

 Topics Covered.

  1. The table structure
  2. A procedure to get the data we need
  3. Producing an xml string from the data
  4. Setting it on the page.

Step 1 Creating the table.

Create a table like the image below. What we will be doing is creating an entryID with is incremental, title, url and descripition for plain text and another int column called parent id to return the parent id of the assigned level.

Now that we have our talbe save it as MenuTable and lets add some content, look at the figure below to see some test data.

So we have both our table and contents setup we need a quick stored procedure to return our dynamic menu. This stored procedure will take 1 variable of parent ID now you will notice in our content i set one item to parent id of 0 this is an id that doesn't exist, and the reason why we did it this way will be very apparent in the coming article.

Back to the Procedure, copy this and create your procedure.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		Nico VanHaaster
-- Create date: 3/20/2009
-- Description:	Gets our menu structure by parent id
-- =============================================
ALTER PROCEDURE MenuTable_getMenuItems
	@parentID int
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;
	
	SELECT *, (SELECT COUNT(*) FROM MenuTable WHERE parentID=main.entryID) ChildCount
	FROM MenuTable main
	WHERE parentID=@parentID ORDER BY title

END
GO

 

So thats all our database work done, now we need to create a class that will return our menu back to the page. We will call this class MenuBuilder (MenuBuilder.cs) and i have commented the information below so i won't go into too much details.

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Web;
using System.Xml;

/// <summary>
/// Summary description for MenuBuilder
/// </summary>
public class MenuBuilder
{
	public MenuBuilder()
	{
	}


    /// <summary>
    /// Returns an XML string for our menu
    /// </summary>
    /// <param name="parentItem">Integer for the parent id, use 0</param>
    /// <returns></returns>
    public string BindMenu(int parentItem)
    {
        //Create our Xml String object as a simple string builder.
        System.Text.StringBuilder xmlText = new System.Text.StringBuilder();

        //Setup our xml header and our home node
        xmlText.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
        xmlText.AppendLine("<siteMap xmlns=\"http://schemas.microsoft.com/AspNet/SiteMap-File-1.0\" >");
        xmlText.AppendLine("<siteMapNode title=\"Home\" description=\"Home\" url=\"default.aspx\" >");

        //Now we would like to append any child nodes with the parent id specified.
        xmlText.AppendLine(AppendChildItem(parentItem));

        //Finish off with our static content, close all the open site tags and return the string back to the original caller
        xmlText.AppendLine("<siteMapNode title=\"Help\" description=\"Help\" url=\"Help.aspx\">");
        xmlText.AppendLine("<siteMapNode title=\"Faq\" description=\"Faq\" url=\"Faq.aspx\" />");
        xmlText.AppendLine("<siteMapNode title=\"User Guides\" description=\"User Guides\" url=\"UserGuides.aspx\" />");
        xmlText.AppendLine("<siteMapNode title=\"Contact Us\" description=\"Contact Us\" url=\"ContactUs.aspx\" />");
        xmlText.AppendLine("</siteMapNode>");
        xmlText.AppendLine("</siteMapNode>");
        xmlText.AppendLine("</siteMap>");
        return xmlText.ToString();
    }


    /// <summary>
    /// Creates the dynamic xml content based on parent id.
    /// </summary>
    /// <param name="parentID"></param>
    /// <returns></returns>
    private string AppendChildItem(int parentID)
    {
        //Create our connection to our stored procedure and fill a datatable with the results.
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MS_SQL"].ConnectionString);
        SqlDataAdapter com = new SqlDataAdapter("MenuTable_getMenuItems", con);
        com.SelectCommand.CommandType = CommandType.StoredProcedure;
        com.SelectCommand.Parameters.AddWithValue("@parentID", parentID);
        DataTable Items = new DataTable();
        com.Fill(Items);

        //Create our child XMl string that will be returned to the BindMenu method.
        System.Text.StringBuilder childXml = new System.Text.StringBuilder();

        //Loop through all rows found from the stored procedure.
        foreach(DataRow reader in Items.Rows)
        {
            //Get the count of child names the current item has
            int ChildCount = Convert.ToInt32(reader["childCount"].ToString());
            //if the node has child nodes enter.
            if (ChildCount > 0)
            {
                //append an opening node with the current data.
                childXml.AppendLine(
                    string.Format("<siteMapNode title=\"{0}\" description=\"{1}\" url=\"{2}\" >", 
                        reader["title"].ToString(),
                        reader["description"].ToString(),
                        reader["url"].ToString()));
                //go back and re-run this method with the new parent id, which is the entry id of this item.
                childXml.AppendLine(AppendChildItem(Convert.ToInt32(reader["entryID"].ToString())));
                //close the tag
                childXml.AppendLine("</siteMapNode>");
            }
            else
                //write a single item for this row.
                childXml.AppendLine(
                    string.Format("<siteMapNode title=\"{0}\" description=\"{1}\" url=\"{2}\" />", 
                        reader["title"].ToString(),
                        reader["description"].ToString(),
                        reader["url"].ToString()));
        }
        //return the childXML string back to bind Menu.
        return childXml.ToString();
    }

}

So now read that over carefully as there are quite alot of mechanics involved. The main piece is re-running the AppendChild Method over and over again as the nodes have childnodes. This will allow infinite number of levels (or until your server runs out of memory).

Finally our Asp.Net Page.

<form id="form1" runat="server">
    <div>
        <asp:Menu runat="server" ID="menu1" DataSourceID="XmlDataSource1" >
            <DataBindings>
                <asp:MenuItemBinding NavigateUrl="url" TextField="title" ToolTipField="description" />
            </DataBindings>
        </asp:Menu>
        <asp:XmlDataSource runat="server" ID="XmlDataSource1" XPath="/*/*" CacheExpirationPolicy="Absolute" EnableCaching="false" />
    </div>
    </form>

 

Code Behind is very simple.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class dynamicMenu : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        MenuBuilder menuObj = new MenuBuilder();
        XmlDataSource1.Data = menuObj.BindMenu(0);

    }
}

 

 

And thats all there is too it.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: dynamic, menu, xml datasource, sql server

C# Asp.Net | Asp.Net Controls | Xml

E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (32) | Post RSSRSS comment feed

Store and Retrieve an image from Database sql server

by Nico 19. March 2009 07:03

Working example here  


Images are vastly becoming the must have for any website, wether they are advertising banners, photo galleries, dynamic images or whatever the needs. The major problem comes around when we have to start keeping track of the images, and ultimatly storing them in a fasion to easily maintain these images.

We will be looking at a few quick topics here along these lines.

  • Creating a database structure to support images
  • Creating our stored procedures to insert and retrieve the images
  • Adding an image to our database
  • Retrieving a thumbnail version of the image while maintaining the aspect ratio
  • Retrieving the full size image
  • Adding this logic to databound controls.

Creating our database table design

In Figure 1 shows our simple database structure which has 3 basic columns and all 3 are vital. You can add your own custom columns as you wish however I have gone with the simplest approach.

  1. imageID, this is the UNIQUE PK of the image, we will be using this number later to figure out which image we are trying to retrieve.
  2. imageBlob, this is the image binary (as you will see upcoming).
  3. imageExtension, this is the physical file extension. We are going to store this for setting our Mime type for the client\server
     

Figure 1

 

 

 

 

 

You can download the script required to build this file.
Create_DynmaicImagesTable.sql (607.00 bytes)

Now that we have our table, lets go create our Sql Stored Procedure to insert a new image into the database table. I have included the script to copy\paste and to download below. You will see it is a simple procedure that will accept two variables, 1 a binary string of the image and the extension of the file. Once inserted we return the imageID generated from the insert command with @@IDENTITY

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		Nico, VanHaaster
-- Create date: 03/19/2009
-- Description:	INSERTS A NEW IMAGE INTO OUR IMAGES TABLE
--              AND RETURNS THE PK
-- =============================================
CREATE PROCEDURE dynamicImages_InsertNewImage
	@imageBlob varbinary(MAX), --Image blob variable
	@imageExtension nvarchar(4) -- Image extension variable
AS
BEGIN
	
	SET NOCOUNT ON;

    --INSERT THE IMAGE INTO THE DATABASE TABLE Dynamic Images
	INSERT INTO dynamic_images (imageBlob,imageExtension) VALUES (@imageBlob,@imageExtension)
    
    --RETURN THE imageID FROM THE INSERT STATEMENT
    SELECT @@IDENTITY
END
GO

You can download the script to create the Stored Procedure
InsertImage_1.sql (741.00 bytes)

Now on to retrieving the image from the database so we can use it later. In this procedure we are going to send 1 variable and recieve both the extension and the Image Binary.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		Nico VanHaaster
-- Create date: 3/19/2009
-- Description:	RETRIEVE THE IMAGE AND EXTENSION BY PK
-- =============================================
CREATE PROCEDURE dynamicImages_getImageById
	@imageID int
AS
BEGIN
	SET NOCOUNT ON;

	SELECT imageBlob,imageExtension FROM dynamic_images WHERE imageID=@imageID

END
GO

You can download the script to create the Stored Procedure
SelectImage.sql (444.00 bytes)

Finally we have one more stored procedure, this one is basic and will be used for our databound gridview. This does not take any parameters and returns a data list of the imageid and the image extension.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		Nico VanHaaster
-- Create date: 3/19/2009
-- Description:	RETRIEVE THE IMAGE AND EXTENSION BY PK
-- =============================================
CREATE PROCEDURE dynamicImages_getAllImages
AS
BEGIN
	SET NOCOUNT ON;

	SELECT imageID,imageExtension FROM dynamic_images

END
GO

You can download the script to create the Stored Procedure
ImagesSelectAll.sql (402.00 bytes)

So thats basically all the Sql work completed. Just a quick checklist, we should have 1 table named dynamic_images that has 3 columns. As well we should have three stored procedures, 1 to insert the image information, 1 to retrieve it and 1 to retrieve all.

Adding an Image to our Database.

This is where the fun begins, what we will be doing is using a very simple .Net page to insert our image into our database. I have provided all the project files at the bottom of the page for you to directly download and use.

The first thing I have done is created a few items in the web.config to handle our database connection. NOTE YOU HAVE TO ENTER YOUR OWN CONNECTION STRING IN (did you really think i was going to include mine?) The first one is in the appSettings setting a key of allowed file extensions. These are comma separated and used to validate wether or not we allow this extension as a valid image file. The second is your standard SQL Server connection string.

<appSettings>
    <add key="AllowedImageExtensions" value=".gif, .png, .bmp, .jpg"/>
  </appSettings>
  <connectionStrings>
    <add name="MS_SQL" connectionString="Data Source=database;uid=user;pwd=password;"/>
  </connectionStrings>

 

Now that we have our extensions setup its time to move to defining a few classes and handlers. A handler is basically a file that produces an individual Http Response. In this case we are going to build two very simalar, one to produce the image, and another to produce the thumbnail of the image.

So i won't go into too much detail on those two files as they have comments in them, and all files are contained in the archive at the bottom.

File Name: GetImage.ashx (produces the image)

<%@ WebHandler Language="C#" Class="GetImage" %>

using System;
using System.Web;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

public class GetImage : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        //set ident to -1 as no image id should be ever -1
        int ident = -1;
        
        //set our photo object to our no image bitmap
        Bitmap photo = new Bitmap(context.Server.MapPath(@"\Images\No_Image.png"));
        
        //test to make sure this is a valid number, if not we simply fall through and not produce an error.
        try
        {
            ident = Convert.ToInt32(context.Request.QueryString["ident"].ToString());
        }
        catch { }
        
        //if ident is no longer -1 we initialize our ImageHandler object and set our photo to the binary recieved.
        if (ident != -1)
        {
            ImageHandler imgObj = new ImageHandler();
            imgObj.GetImage(ident);
            photo = imgObj.photo;
        }

        //you can specify actual widths and height, we do this here you can specify your own height\width if you wish.
        int width = photo.Width;
        int height = photo.Height;
        Bitmap target = new Bitmap(width, height);
        using (Graphics graphics = Graphics.FromImage(target))
        {
            graphics.CompositingQuality = CompositingQuality.HighSpeed;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.DrawImage(photo, 0, 0, width, height);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                target.Save(memoryStream, ImageFormat.Png);
                memoryStream.WriteTo(context.Response.OutputStream);
            }
        }
        photo.Dispose();
        target.Dispose();
        context.Response.End();
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }

}

 

File Name: GetImageThumbnail.ashx (produces the thumbnail)<%@ WebHandler Language="C#" Class="GetImageThumbnail" %>

using System;
using System.Web;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

public class GetImageThumbnail : IHttpHandler {
    ///
    /// specifies the thumbnail max size.
    ///
    private int _thumbnailSize = 125;
    public void ProcessRequest (HttpContext context) {
        //set ident to -1 as no image id should be ever -1
        int ident = -1;

        //set our photo object to our no image bitmap
        Bitmap photo = new Bitmap(context.Server.MapPath(@"\Images\No_Image.png"));

        //test to make sure this is a valid number, if not we simply fall through and not produce an error.
        try
        {
            ident = Convert.ToInt32(context.Request.QueryString["ident"].ToString());
        }
        catch { }

        //if ident is no longer -1 we initialize our ImageHandler object and set our photo to the binary recieved.
        if (ident != -1)
        {
            ImageHandler imgObj = new ImageHandler();
            imgObj.GetImage(ident);
            photo = imgObj.photo;
        }

        //you can specify actual widths and height, we do this here you can specify your own height\width if you wish.
        context.Response.ContentType = "image/png";
       
        //declare our height & width objects
        int width, height;
        //do the process of resizing our image to our specified height\width
        if (photo.Width > photo.Height)
        {
           
            width = 125;
            height = photo.Height * _thumbnailSize / photo.Width;
        }
        else
        {
            width = photo.Width * _thumbnailSize / photo.Height;
            height = _thumbnailSize;
        }
        //return the photo to the browser
        Bitmap target = new Bitmap(width, height);
        using (Graphics graphics = Graphics.FromImage(target))
        {
            graphics.CompositingQuality = CompositingQuality.HighSpeed;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.DrawImage(photo, 0, 0, width, height);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                target.Save(memoryStream, ImageFormat.Png);
                memoryStream.WriteTo(context.Response.OutputStream);
            }
        }
        photo.Dispose();
        target.Dispose();
        context.Response.End();
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

And here is the meat and potatoes, the main image class

ImageHandler.cs

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Web;

/// 
/// Main class for your image Handeling
/// 
public class ImageHandler
{
    public int ImageID { get; set; }
    public Bitmap photo { get; set; }
    public string ImageExtension { get; set; }

    public void InsertImage(string extension,byte[] imageBlob)
    {
        SqlConnection _con = new SqlConnection(ConfigurationManager.ConnectionStrings["MS_SQL"].ConnectionString);
        SqlCommand _com = new SqlCommand("dynamicImages_InsertNewImage", _con);
        _com.CommandType = CommandType.StoredProcedure;
        _com.Parameters.AddWithValue("@imageBlob", imageBlob);
        _com.Parameters.AddWithValue("@imageExtension", extension);
        _con.Open();
        ImageID = Convert.ToInt32(_com.ExecuteScalar().ToString());
        _con.Close();
    }

    public void GetImage(int imageID)
    {
        SqlConnection _con = new SqlConnection(ConfigurationManager.ConnectionStrings["MS_SQL"].ConnectionString);
        SqlCommand _com = new SqlCommand("dynamicImages_getImageById", _con);
        _com.CommandType = CommandType.StoredProcedure;
        _com.Parameters.AddWithValue("@imageID", imageID);
        _con.Open();
        MemoryStream stream = new MemoryStream();
        try
        {
            SqlDataReader reader = _com.ExecuteReader();
            if (reader.Read())
            {
                byte[] image = (byte[])reader["imageBlob"];
                ImageExtension = reader["imageExtension"].ToString();
                stream.Write(image, 0, image.Length);
                photo = new Bitmap(stream);
            }
            else
                photo = new Bitmap(HttpContext.Current.Server.MapPath(@"\Images\no_image.png"));
            reader.Close();
        }
        catch
        {
        }
        finally
        {
            stream.Close();
            _con.Close();
        }
    }
    public DataTable GetAllImages
    {
        get
        {
            SqlConnection _con = new SqlConnection(ConfigurationManager.ConnectionStrings["MS_SQL"].ConnectionString);
            SqlDataAdapter da = new SqlDataAdapter("dynamicImages_getAllImages", _con);
            da.SelectCommand.CommandType = CommandType.StoredProcedure;
            DataTable dt = new DataTable();
            da.Fill(dt);
            return dt;
        }
    }
}

Upload Image.aspx

<strong>Upload the image into the database.</strong><br />
<asp:Label runat="server" ID="errLbl" Style="display:block;" ForeColor="Red" Visible="false" />
Select File  <asp:FileUpload runat="server" ID="fup1" />  <asp:Button runat="server" ID="upload_btn" Text="Upload Image" OnClick="upload_btn_click"  /><br />
<span class="small_text">Accepted file types: <%= ConfigurationManager.AppSettings["AllowedImageExtensions"].ToString().ToLower() %>.</span><br />

Upload Image.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class UploadFile : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        
    }


    /// 
    /// Handels when the user clicks the upload button.
    /// 
    protected void upload_btn_click(object o,EventArgs args)
    {
        errLbl.Visible = false;
        string ext = System.IO.Path.GetExtension(fup1.FileName).ToLower();
        string filename = fup1.FileName.Replace(ext, string.Empty).Replace(" ", "-").ToString();
        if (filename.Length > 255)
            filename.Substring(0, 200);
        //split our AllowedImageExtensions string up into an array.
        string[] a_ext = System.Configuration.ConfigurationManager.AppSettings["AllowedImageExtensions"].ToString().ToLower().Replace(" ", "").Split(new char[] { ',' });
        bool allow_ext = false;
        foreach (string e in a_ext)
            if (e == ext)
                allow_ext = true;
        //make sure the allow extension is true if not throw an error
        if (!allow_ext)
        {
            errLbl.Text = "Invalid File Extension.";
            errLbl.Visible = true;
            return;
        }
        int len = fup1.PostedFile.ContentLength;
        byte[] data = new byte[len];
        fup1.PostedFile.InputStream.Read(data, 0, len);
        ImageHandler imageObj = new ImageHandler();
        imageObj.InsertImage(ext, data);
        Response.Redirect(string.Format("ViewImage.aspx?ident={0}&falseNoCacheSession={1}", imageObj.ImageID, Guid.NewGuid().ToString()));
        return;
    }
}
ViewImage.aspx
View Your Image<br />
<asp:LinkButton runat="server" ID="view_thumbnail" OnClick="view_thumbnail_click" Text="View Thumbnail" />    
<asp:LinkButton runat="server" ID="view_fullsize" OnClick="view_fullsize_click" Text="View Full Size" Visible="false" />
<br />
<asp:Image runat="server" ID="view_image" AlternateText="Preview Your Image File" /><br /><br />
ViewImage.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ViewImage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            view_thumbnail.Visible = false;
            view_fullsize.Visible = true;
            if (Request.QueryString["ident"] != null)
                view_image.ImageUrl = string.Format("GetImageThumbnail.ashx?ident={0}",Request.QueryString["ident"].ToString());
            else
                view_image.ImageUrl = "Images/No_Image.png";

        }
    }

    protected void view_thumbnail_click(object o, EventArgs e)
    {
        view_thumbnail.Visible = false;
        view_fullsize.Visible = true;
        if (Request.QueryString["ident"] != null)
            view_image.ImageUrl = string.Format("GetImageThumbnail.ashx?ident={0}", Request.QueryString["ident"].ToString());
        else
            view_image.ImageUrl = "/Images/No_Image.png";

    }

    protected void view_fullsize_click(object o, EventArgs e)
    {
        view_thumbnail.Visible = true;
        view_fullsize.Visible = false;
        if (Request.QueryString["ident"] != null)
            view_image.ImageUrl = string.Format("GetImage.ashx?ident={0}", Request.QueryString["ident"].ToString());
        else
            view_image.ImageUrl = "Images/No_Image.png";

    }
}
ImagesDataBound.aspx
<asp:GridView runat="server" ID="view_all_grid" AutoGenerateColumns="false" Width="100%" BorderStyle="None" CellPadding="5" CellSpacing="0" GridLines="None">
    <RowStyle HorizontalAlign="Center" />
    <Columns>
        <asp:TemplateField>
            <HeaderTemplate>Image</HeaderTemplate>
            <ItemTemplate>
                <a href='<%# GetViewLink(DataBinder.Eval(Container.DataItem,"imageID").ToString()) %>'><img border="0" src='<%# CreateImageSource(DataBinder.Eval(Container.DataItem,"imageID").ToString()) %>' alt="Click to view this image" /></a>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField>
            <HeaderTemplate>Image Type (extension)</HeaderTemplate>
            <ItemTemplate>
                <%# Eval("imageExtension") %>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
strong>ImagesDataBound.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ImagesDataBound : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            ImageHandler imgObj = new ImageHandler();
            view_all_grid.DataSource = imgObj.GetAllImages;
            view_all_grid.DataBind();
        }
    }

    protected string CreateImageSource(string ident)
    {
        return string.Format("GetImageThumbnail.ashx?ident={0}", ident);
    }

    protected string GetViewLink(string ident)
    {
        return string.Format("ViewImage.aspx?ident={0}", ident);
    }
}
And wow thats all of it, now i suggest downloading the solution below and discovering yourself how this all works.
Download Source Code.

DynamicImages.zip (241.35 kb)

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: images, generic handlers, sql server, thumbnails

C# Asp.Net

E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (36) | Post RSSRSS comment feed

Setting up BlogEngine Subdirectory

by Nico 5. March 2009 05:20

Who doesn't love blog engine? I have used it a few times and have gone through one of two routes to set it up and get it working correctly. If you have one of the following two install types below don't look into this document as it will be pointless.

  1. You have your own subdomain to set this up on. ie http://blog.somecompany.com/
  2. You have the ability to convert a subfolder to an IIS Application to contain the folders.

Why do we need to know that? Easy. Blog Engine was originally designed with a few specific Paths and specific locations for their files and other locations. Even the core which is a bunch of classes and objects that make this all work reference these paths.


Get to the point!!

What I have done after ALOT of googling, researching forums, posts, tutorials etc.. have created 2 different packages depending on your IIS Configuration. These packages are designed to allow blog engine to work from a Sub Directory and not required to be is own Application or a subdomain. And if your like me and pay BOTTOM dollar for your hosting company you know all to well how this works.

I have included two files
BlogEngine_IIS7 - For IIS 7 and
BlogEngine_IIS6 - For IIS 6

The reason for the two different packages are the because of the way IIS 7 handles the HttpContext Responses, and also location of objects inside the web.config.

To Use these files.
Extract the zip archives to a new Website (yes lets use a blank website) and open the website in visual studio and run it. Once you have run the application navigate to http://localhost/blogengine (or whatever the address should be with blogengine as its subdirectory) and you should have a fully functioning BlogEngine that is in a sub directory of a regular .Net 3.5 web site.

Some things to note.
The subdirectory is BlogEngine and that is very important to know. If you need to change this follow the steps below.

Open the web.config and  change <add key="BlogEngine.VirtualPath" value="~/BlogEngine/"/> to <add key="BlogEngine.VirtualPath" value="~/SomeDirectory/"/> (replacing some directory with your own)
Also change <add key="StorageLocation" value="~/App_Data/BlogEngine/"/> to <add key="StorageLocation" value="~/App_Data/SomeDirectory/"/>  this might seem pointless but somehow without this your posts are never found.

You will notice in the App_Data, App_Code & App_GlobalResources that the BlogEngine files are in their own subdirectory. ie /App_Data/BlogEngine/ each of the folders App_Data, App_Code, & App_GlobalResources must have the subfolder changed as well to the different name you specified in the Web.Config.

I have put my own spin on this Blog Engine (ok very small but important to me)

The editor (the one i am typing in now) doesn't come with our Beloved Syntax Highlighter (for all of you that have never seen it http://code.google.com/p/syntaxhighlighter/), but what is a syntax highlighter if there isn't a great way to implement it. I don't want to go into the source code on every post and fill this stuff in, i want a nice text pad to enter it for me. Well i have also found a decent one, fought with it, swore at it. Even deleted it and then came back to it. Thanks to this guys blog (http://weblogs.asp.net/nawaf/archive/2008/04/06/syntaxhighlighter-plugin-for-tinymce-wysiwyg-editor.aspx) i was able to fix it, after some tweaking of their javascript to not use TextBlocks, cause well they are ugly

So the editor has a button to insert code snippets, the google syntax highlighter is already installed on the STANDARD only theam, but if you want to put it on any theme you download just place the code below (notice the nice syntax higlighter.. ohh baby)


    
    <link type="text/css" rel="stylesheet" href="/css/SyntaxHighlighter.css" />

<script language="javascript" src="/js/shCore.js" mce_src="/js/shCore.js"></script>
    <script language="javascript" src="/js/shBrushCSharp.js" mce_src="/js/shBrushCSharp.js"></script>
    <script language="javascript" src="/js/shBrushXml.js" mce_src="/js/shBrushXml.js"></script>
    <script language="javascript">

        window.onload = function() {
            dp.SyntaxHighlighter.ClipboardSwf = '/js/clipboard.swf';
            dp.SyntaxHighlighter.HighlightAll('code');
        }
    </script>
    


Customizing the Standard Skin
With some simple css you can easily customize the standard skin that comes with it. I have started with my own Obilit theme (as you can see) i won't get into detail here, however the main file you are looking for is /BlogEngine/Themes/Standard/style.css  the easiest way is to just look at the source code from the browser, find the classes and tweak them.

Problems.
If you run into any problems while installing either of the two packages please leave a comment and i will try my best to help out.

Packages and Files
BlogEngine_IIS6.rar (1.53 mb)


BlogEngine_IIS7.rar (1.53 mb)

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: blogengine, blog, engine, subdirectory, tiny mce, google syntax highlighter, code highlight, iis 7, iis 6

Blog Engine Install

E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (7) | Post RSSRSS comment feed
5 Cranwell Close, Chippenham Wiltshire, SN14 0QG
Obilit © 2008