|
2 Pages 1 2 >
|
|
|
|
|
25 Nov, 2008 - 03:48 PM
|
Today Michael Vick, you know the one, the one who was running a dog fighting ring in his home in Virginia, yeah that Michael Vick, plead guilty to state dog fighting charges in return for a suspended three year sentence and four years probation. Does this disgust anyone other than me? How come, just because a person is rich and famous, they can get away with things the average joe would spend many a year in prison for. I mean Vick got a total of 32 months, 23 for Gods sake.I've know people who got more than that for possession of marijuana. So now having some weed is a far worse crime than dog fighting?
Vick, being the upstanding citizen that he is, has applied for a a prison-monitored drug rehabilitation program, not only that but he could possible be back throwing passes in the NFL by the 2009 season. I'm not sure what is worse, the fact that he could be back playing in the NFL next season, or the NFL scouts that went to Leavenworth to scout him while he was playing prison football.
As a dog owner, and a life long animal owner, I believe Vick committed one of the worst crimes imaginable (well except for some crimes against people who can actually defend themselves) and should be sitting in his cell for eternity. How can any NFL owner even contemplate bringing Vick onto his team, how can any owner think it's ok to sweep what he has done under the rug just to have him on his team.
I firmly believe that if Vick is offered a position on any NFL team the entire league should be boycotted, plain and simple. Someone needs to show these money grubbing owners that we may be football fans, and some of us avid fans, but we are more than willing to draw the line at allowing a person who plead guilty to one of the worst sports (and I use that term loosely) to put on your uniform and represent your team each and every Sunday.
But what do I expect, Adam Pacman Jones has been arrested (or involved with a crome) over 14 times in his career and he was just recently reinstated so he can continue to play the game that so many players love. Do you think Favre, Montana or even Joe Namath would behave in such a manner? If Vick is allowed to come back and play in the NFL it will be the darkest day in the National Football League, bar none.
| |
|
|
|
|
|
|
|
5 Nov, 2008 - 09:42 AM
|
McCain maybe a national hero but I felt he was really disconnected with the American people, while I truly felt that Obama was coming from the heart and was sincere with what he said. If you look at the campaign, not once, even during the debates when many said he would lose, he never lost his confidence, never was intimidated and never lost his resolve to win this thing.
I felt towards the end that McCain was accepting the inevitable, that he was going to lose this election, though I don't think he thought we would lose this bad (I mean he lost Virginia, Indiana, Florida, Nevada, New Mexico and Ohio, which were all Republican states in 04, and may well lose North Carolina, since they haven't called that one yet).
I hope Republican supporters don't start calling the election rigged, especially wince it was a lopsided victory. Obama has said all along that his list of priorities are (in order) the economy, health care, education and Iraq, and I truly believe he will stick to that plan.
My wife, who is a staunch Democrat said that in the beginning she thought McCain was being sincere and believed what he was saying, then as time went on and he started the smear campaign he lost that.
I hope Republicans learn something from this, that old style campaigns of slamming and attacking your opponent don't work anymore. The American people are tired of that, and the more McCain did it the further he got behind in the polls. It even happened in the House and Senate, even my state, where the Democrat won 4 years ago by only 129 votes, ran against the same Republican, who decided to use the attack/smear campaign tactics and this time he lost by over 50,000 votes.
America was dieing for a change, and they spoke with conviction last night, and left no doubt who they thought would bring about this change. Whether anyone wants to recognize it or not last night was history in the making, last night was the most historic election in this long history of this country. Last night the American people showed that they could look over the ethnicity of a candidate and focus on what they thought he could bring to the table.
A new era was ushered in last night, I really feel that Obama is just the breath of fresh air this country needed. Obama ran a campaign unlike any other, he made it to the White House without lofty promises of pork barrel spending, earmarks for this who supported him. I really this, whether Republican or Democrat, we should all embrace this new era, and look forward to what changes this can bring about for this country.
| |
|
|
|
|
|
|
|
31 Oct, 2008 - 04:31 PM
|
There is a continuing debate on the pros and cons of using Global variables. Some say they are flat out bad and you should never use them, some say that they are an acceptable form of storing global values, as long as they are used sparingly. I feel both sides are correct, I think there is no one size fits all solution for this issue, and I believe they should be looked at from an application to application basis. For procedural programming I feel they are completely acceptable, and sometimes no way around them, for OO programming, however, I feel there are many better alternatives to using global variables. I will say that application level globals are very bad practice, but if you truly need something globally across an entire application then you should look at the Singleton approach, which allows only a single (or set number) instance of an object to be used across the entire application. Using the Singleton approach also lends itself to Lazy evaluation and isntantiation, which will increate performance over global variables because the global variable will always consume resources (in most programming languages anyways). Global variables can result in a child process altering the value of your variable without the parent process being aware of, thus causing invalid results and creating a bug that's nearly impossible to track down. Global variables also pollute the namespace, and can, at times can cause name collision. When thinking of scalability and the flexibility of your program then stay away from using global variables. If you find yourself creating and using global variables, you should stop and re-think your design approach, that's just my opinion of course. If you need values across the entire scope of your application, you might want to take a look at a struct, an enum, or even using const in your classes, but you should really limit your use of global variables.
| |
|
|
|
|
|
|
|
17 Aug, 2008 - 06:33 AM
|
Recently I have seen several questions regarding using Scrollbar's in a PictureBox. While this can be done, and is done quite often, I personally prefer to scale the image down to fit within the dimensions of the PictureBox that's holding the image. Some will ask how it's possible to accomplish this without distorting the image itself, some will ask how it's even possible to begin with. Given these questions I thought it would be a nice test to see if I could do this without degrading the image too bad, regardless of the image size or the size of the PictureBox. For the first question, in order to change (or scale) and image liek this without degrading the quality too bad you would want to re-draw the image once it's re-sized, thus clearing the image up. To accomplish this you play around with the InterpolationMode, which is located in the System.Drawing.Drawing2D Namespace. For this example we will be setting it to HighQualityBicubic, which is used to make sure the quality stays put while shrinking the image. The first thing we will do is to write a method which returns a Size, which will hold the new height and width of our image. This method will require four parameters: - Current Height (height of the image)
- Current Width (width of the image)
- Destination Height (the height we want)
- Destination Width (the width we want
The first two we will be getting from our image itself, the final two will come from the dimensions of the PictureBox housing the image. We will ensure proper scaling by doing everything based on a multiplier, and that will be calculated based on whether the image is landscape or portrait style. Here is how we calculate the new dimensions of our image: csharp public Size GenerateImageDimensions(int currW, int currH, int destW, int destH) { //double to hold the final multiplier to use when scaling the image double multiplier = 0;
//string for holding layout string layout;
//determine if it's Portrait or Landscape if (currH > currW) layout = "portrait"; else layout = "landscape";
switch (layout.ToLower()) { case "portrait": //calculate multiplier on heights if (destH > destW) { multiplier = (double)destW / (double)currW; }
else { multiplier = (double)destH / (double)currH; } break; case "landscape": //calculate multiplier on widths if (destH > destW) { multiplier = (double)destW / (double)currW; }
else { multiplier = (double)destH / (double)currH; } break; }
//return the new image dimensions return new Size((int)(currW * multiplier), (int)(currH * multiplier)); }
Now wew have our new dimensions, so lets apply that to our image, and make sure we adjust the image to retain as much or the original quality as possible csharp private void SetImage(PictureBox pb) { try { //create a temp image Image img = pb.Image;
//calculate the size of the image Size imgSize = GenerateImageDimensions(img.Width, img.Height, this.pictureBox1.Width, this.pictureBox1.Height);
//create a new Bitmap with the proper dimensions Bitmap finalImg = new Bitmap(img, imgSize.Width, imgSize.Height);
//create a new Graphics object from the image Graphics gfx = Graphics.FromImage(img);
//clean up the image (take care of any image loss from resizing) gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
//empty the PictureBox pb.Image = null;
//center the new image pb.SizeMode = PictureBoxSizeMode.CenterImage;
//set the new image pb.Image = finalImg; } catch (System.Exception e) { MessageBox.Show(e.Message); } }
Believe it or not that's it! We have just proportionately scaled an image to fit within our PictureBox, and maintained as much of the original images quality as possible. To use this we can add it into the Load event of a Forum, or even in the Click event of a button, like so csharp private void Form1_Load(object sender, EventArgs e) { SetImage(pictureBox1); }
I hope this small bit of code was useful, and Ill be doing more writing in the future on working with images and GDI with the .Net Framework. Thanks for reading
| |
|
|
|
|
|
|
|
24 Jul, 2008 - 11:37 AM
|
Back in the day of Visual Basic 6 there wasn’t much of a debate VB6 was the Windows ME of programming languages. Though VB6 had its place, it wasn’t really recognized as a programming language by the world of “real” programmers. Fast forward to the release of .Net, old VB6 programmers could finally use an OO language and almost be recognized as a real programmer, but could they really? With VB.NET came C#, a language modeled after C++ and Java, “true” languages to the programming purists, a language often referred to as C++’s little brother. Then the debate began, a heated debate at that; which language was better? Programming purists argued, and still do to this day, that C# is the better language, but is it really? In this article we will take a look at both sides and I will place my opinion into this debate, whether it be for better or worse. Though I prefer to program in C# since I come from a C/C++ background, I am certified in both and believe both have their own place. Since both languages are converted to Microsoft Intermediate Language (MSIL), both are then converted into machine code via the Common Language Runtime (CLR) when the program is run, and both languages are built on the same Framework, why are so many spending so much time arguing over which language is the better language? Here are a couple of the largest differences between C# and VB.NET - C# supports unsafe code: Though this is really something that should be avoided, unless you have no choice.
- C# supports pointers, kind of: This can lead to corrupt memory so this too should probably be avoided.
- C# supports explicit interfaces: Something I avoid at all costs
- C# is a strongly typed language, whereas VB.NET is much more forgiving
- C# does not support passing referenced types by value
- VB.NET has better support for COM Interop
- VB.NET supports unstructured error handling
- VB.NET supports optional parameters
- VB.Net supports passing objects by reference and by value
- VB.NET has easier implementation of late binding
Now here are some areas where the two are identical: - Both use the same .Net Framework
- Both support:
- Inheritance
- Polymorphism
- Interfaces
- Generics
- Overloading
- Both are compiled to MSIL
- Both rely on the CLR
- Both are Object Orientated languages (Yes VB.NET is a true Object Orientated language)
When looking at that list, I truly don’t see a clear cut reason for saying that either language is the superior language, they both have their advantages and disadvantages, and they both have things they may be better at than the other. In VB.NET performing late binding is much simpler, whereas with C# you must handle the late binding in code utilizing Reflection, whereas with VB.NET the compiler can implement it for you. Do the languages differ, yes they do, does this mean that one is better than the other, I would have to say this is a resounding no. Visual Basic has come a long way since its inception, it is no longer a “toy” language, and should be treated the same as C#. In the end it boils down to personal preference when choosing a .Net language to work in, as there is really no clear cut winner in the “Which language is superior” argument. Simply chose the language you're the most comfortable with, and know that both will end up with the same results for your application So as you can see this argument is really a waste of time, both are fine languages, both will get you to the same end result.
| |
|
|
|
|
|
|
|
31 May, 2008 - 09:49 AM
|
In a previous post I discussed manipulating images using GDI+, today we're going to look at working with images using a custom HttpHandler that implements the IHttpHandler Interface. This tutorial is on the advanced side and makes a couple assumptions: So if you are new to the programming/C# world some of the items covered may seem complicated, but I will do my best to provide links to the items we are looking at. This will be a multi-part series on manipulating images with out HttpHandler, in this we will look at creating nice thumbnails of our images with the HTTP request. This may end up being quite long, so setting in for some reading and learning. First we need is our HttpHandler class. This class will be marked with the abstract modifier so we can inherit from it in our thumbnail class. First, as with any class we build in C#, we need references to the appropriate Namespaces, for this class we need the following Namespaces csharp using System; using System.Collections.Generic; using System.Text; using System.Web; using System.Net;
When we inherit from a base class (in our case an Interface) you need to include that in your class's signature. You can name your class anything you like, mine just so happens to be named RLMHttpHandler csharp public abstract class RLMHttpHandler : IHttpHandler { //class body will go here }
In our base class we have 3 properties, 2 will be overridden in our thumbnail class, the other is read-only and always returns true (as we want this class to be reusable) csharp #region Properties /// <summary> ///does handler need authentication /// </summary> public abstract bool RequiresAuthentication { get; }
/// <summary> ///get the MIME Type. /// </summary> public abstract string ContentMimeType { get; }
/// <summary> /// is this reusable /// </summary> public bool IsReusable { get { return true; } } #endregion Properties
Since our class is marked with abstract we are able to have abstract methods in our class. Marking a method with abstract means those methods must be implemented by any class that inherits our handler class. When we implement them in our thumbnail class we will need to mark them with the override modifier so that we can extend the methods. Here are the two abstract methods csharp /// <summary> ///method for handling the request This is where you put your business logic. /// </summary> /// <param name="context">the current HttpContext</param> protected abstract void HandleRequest(HttpContext context);
/// <summary> /// validates the parameters. Inheriting classes must implement this and return /// true if the parameters are valid, otherwise false. /// </summary> /// <param name="context">the current HttpContext</param> /// <returns></returns> public abstract bool ValidateParameters(HttpContext context);
Next we will look at the main (primary) method of our handler class, aptly named ProcessRequest. Here is where we will set the cache policy (meaning to allow or disallow caching of the images being processed), we will make sure we have access to the current resource and make sure all request parameters are valid. csharp /// <summary> ///processs the incoming HTTP request. /// </summary> /// <param name="context">the current HttpContext</param> public void ProcessRequest(HttpContext context) { //set the cache policy this.SetResponseCachePolicy(context.Response.Cache);
//make sure all parameters were validated successfully, //otherwise respond with an error if (!(this.ValidateParameters(context))) { this.RespondInternalError(context); return; }
//make sure we have access to the resource if (this.RequiresAuthentication && (!(context.User.Identity.IsAuthenticated))) { //no access so return a forbidden access error this.RespondForbidden(context); return; }
context.Response.ContentType = this.ContentMimeType; this.HandleRequest(context); }
Now for the four methods that are called upon in our ProcessRequest method. First is the SetResponseCachePolicy method, this is where we tell our handler whether it's safe to cache the thumbnails or not csharp /// <summary> /// set the cache policy. /// Unless overridden handler will not allow a response to be cached. /// </summary> /// <param name="cache">the current HttpContext</param> public void SetResponseCachePolicy(HttpCachePolicy cache) { cache.SetCacheability(HttpCacheability.NoCache); cache.SetNoStore(); cache.SetExpires(DateTime.MinValue); }
The next three just work with generating the error message that may (or may not) be needed csharp /// <summary> /// method for responding to any error in the current request /// </summary> /// <param name="context">the current HttpContext</param> protected void RespondInternalError(HttpContext context) { context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; context.Response.End(); }
/// <summary> /// method to send forbidden response when request is trying /// to access a forbidden resource /// </summary> /// <param name="context">Context.</param> protected void RespondForbidden(HttpContext context) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; context.Response.End(); }
/// <summary> /// method to send a file not found response if the /// image isng found /// </summary> /// <param name="context">Context.</param> protected void RespondFileNotFound(HttpContext context) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.End(); }
Okay, we now have our HttpHandler completed, it is ready for us to implement in our thumbnail class, so lets create the thumbnail class. First our Namespace references csharp using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Web; using System.Web.UI; using System.Drawing.Imaging; using System.Reflection; using System.Drawing;
In out thumbnail class we offer different size thumbnails to be generated, we handle this with a simple enumerationcsharp #region Enumerations /// <summary> ///enum for handling the size of the thumbnail /// to be generated by this request /// </summary> internal enum Size { Small = 72, Medium = 144, Large = 288 } #endregion Enumerations
That takes care of the thumbnail size problem. Next we have a couple variables, marked with the const modifier, telling the class that these values can never change, and a couple class level variables csharp #region Constants // Declare and define global constants that come //from the QueryString of thr current request private const string IMG_PARAM = "img"; // image parameter private const string SIZE_PARAM = "sz"; // size parameter
//default thumbnail private const string DEFAULT_THUMBNAIL = "NotAvailable.gif"; #endregion
#region Globals /// <summary> /// MIME text for this request /// </summary> private string _mimeText = "image/gif";
/// <summary> /// ImageFormat for this request /// </summary> private ImageFormat _formatType = ImageFormat.Gif;
/// <summary> /// size of this thumbnail /// </summary> private Size _sizeType = Size.Small; #endregion
Now we get into the heart of our thumbnail class. First we will look at the methods for our thumbnail class, then the override methods from our HttpHandler class. The methods we will be looking at are - ValidImage: This method determines if we're dealing with a valid image file. Here, if we have a valid image we will set out MimeText and FormatType global values. If it's not a valid image file we return false to stop the process
- SetThumbnailSize: This method will set the size of the thumbnail we are creating
- CreateThumbnail: This method will do the creation of the thumbnail. This method will use math to determine, based on the current size of the image, what the proper dimensions are for an accurate thumbnail image. Unlike the first 2 this method returns an Image type rather than being a void
- GetDefaultImage: This method will get the default image we specify. This only comes into play if the image we're looking for doesnt exist
So lets look at them one at a time: ValidImagecsharp /// <summary> ///method to determine if we have a valid image or not /// </summary> /// <param name="fileName">File name from the img parameter.</param> /// <returns> /// </returns> private bool ValidImage(string file) { //get the extension of the file name passed string extension = Path.GetExtension(file).ToLower(); //bool to hold whether it's valid or not bool isValid = false;
//now determine the extension switch (extension) { case ".jpg": case ".jpeg": isValid = true; this._mimeText = "image/jpeg"; this._formatType = ImageFormat.Jpeg; break; case ".gif": isValid = true; this._mimeText = "image/gif"; //this._formatType = ImageFormat.Gif; this._formatType = ImageFormat.Jpeg; break; case ".png": isValid = true; this._mimeText = "image/png"; //this._formatType = ImageFormat.Png; this._formatType = ImageFormat.Jpeg; break; default: //since it's not an image extension we return false isValid = false; break; } return isValid; }
SetThumbnailSizecsharp /// <summary> /// Sets the size of the thumbnail base on the size parameter. /// </summary> /// <param name="value">The size parameter.</param> private void SetThumbnailSize(string value) { //int to hold the converted size value int size;
//if we cant parse the value (meaning no valid number provided) we set //the thumbnail size to medium if (!(Int32.TryParse(value.Trim(), System.Globalization.NumberStyles.Integer, null, out size))) size = (int)Size.Medium;
//since the value parsed correctly now we set the size try { this._sizeType = (Size)size; } catch { this._sizeType = Size.Medium; } }
CreateThumbnailcsharp /// <summary> /// This method generates the actual thumbnail. /// </summary> /// <param name="src"></param> /// <returns>Thumbnail image</returns> private Image CreateThumbnail(Image src) { int max = (int)this._sizeType;
int width = src.Width; int height = src.Height;
if (width > max) { height = (height * max) / width; width = max; }
if (height > max) { width = (width * max) / height; height = max; }
// The third parameter is required and is of type delegate. Rather then create a method that // does nothing, .NET 2.0 allows for anonymous delegate (similar to anonymous functions in other languages). return src.GetThumbnailImage(width, height, delegate() { return false; }, IntPtr.Zero); }
GetDefaultImagecsharp /// <summary> /// Get default image. /// </summary> /// <remarks>
/// This method is only invoked when there is a problem with the parameters. /// </remarks> /// <param name="context"></param> private void GetDefaultImage(HttpContext context) { Assembly assembly = Assembly.GetAssembly(this.GetType()); Stream imageStream = null; Bitmap bitmap = null; string file = string.Format("{0}{1}{2}", DEFAULT_THUMBNAIL, (int)this._sizeType, ".gif");
imageStream = assembly.GetManifestResourceStream(assembly.GetName().Name + file); if (imageStream != null) { bitmap = (Bitmap.FromStream(imageStream) as Bitmap); bitmap.Save(context.Response.OutputStream, this._formatType);
imageStream.Close(); bitmap.Dispose(); } }
Now we have our image manipulation methods accounted for, and by now you're asking (yes I can hear you) about the HttpHandler class we are supposed to be using. Well now we get to that, now we will take a look at our base class methods and getting them to dow hat we want, make thumbnail images. First we need to override the abstract properties from our handler class, the first will return false (requires authentication property), and the MIME text we set in ValidImagecsharp /// <summary> ///tell base class we dont need authentication /// </summary> /// <value> /// </value> public override bool RequiresAuthentication { get { return false; } }
/// <summary> //tell the base class our MIME text /// </summary> public override string ContentMimeType { get { return this._mimeText; } }
Now we have two abstract methods from our base class we need to account for. We're going to go the lazy way for ValidateParameters and just always return true. We do this because if there is a problem we just return a default image in it's place. csharp /// <summary> ///always return true for this, GetDefaultImage will handle any errors /// </summary> /// <param name="context"></param> /// <returns></returns> public override bool ValidateParameters(HttpContext context) { return true; }
Last but not least we need to override the abstract HandleRequest method of our base class. Here we will check the size parameter passed, along with the image parameter passed. If image parameter isnt present we simply retrieve the default image, if no size is provided we default to a medium thumbnail. csharp /// <summary> ///override the HandleRequest from our base class and use it /// to create our thumbnails /// </summary> /// <param name="context"></param> protected override void HandleRequest(HttpContext context) { //if no size is provided default to small if (string.IsNullOrEmpty(context.Request.QueryString[SIZE_PARAM])) this._sizeType = Size.Small; //otherwise set out thumbnail size else this.SetThumbnailSize(context.Request.QueryString[SIZE_PARAM]);
//if no image was provided get the default image if ((string.IsNullOrEmpty(context.Request.QueryString[IMG_PARAM])) || (!(this.ValidImage(context.Request.QueryString[IMG_PARAM])))) this.GetDefaultImage(context); else { string file = context.Request.QueryString[IMG_PARAM].Trim().ToLower().Replace("\\", "/");
//if our parameter doesnt contain a forward slash we need to add one if (file.IndexOf("/") != 0) file = "/" + file;
//check to see if the image exist, if not grab the default image if (!(File.Exists(context.Server.MapPath("~" + file)))) { this.GetDefaultImage(context); } else { //image exists so create our thumbnail and save it to //the current HttpContext's output stream using (System.Drawing.Image im = System.Drawing.Image.FromFile(context.Server.MapPath("~" + file))) using (System.Drawing.Image tn = this.CreateThumbnail(im)) { tn.Save(context.Response.OutputStream, this._formatType); } } } }
Now our code for creating thumbnails via a Http Request, but unfortunately we're not done there. First, in the web.config file of the web application we're using this in we need to register a new HttpHandler. The syntax for adding a new HttpHandler to your web.config is CODE <httpHandlers> <add verb="verb list" path="path/wildcard" type="type,assemblyname" validate="true|false"/> </httpHandler>
The one I added to my web.config look like this CODE <httpHandlers> <add verb="*" path="ImageThumbnail.ashx" type="RLM.ImageHandler.Thumbnail, RLMImageHandler"/> </httpHandlers>
Where RLM.ImageHandler.Thumbnail is the name of the type Im using and RLMImageHandler is the actual name of the assembly. ImageThumbnail.ashx is where the requests will be sent and processed (though ImageHandler.ashx isnt an actual, physical page in our application). Now all we need is a page to work with. We will use an Image Server Control for displaying our image. I will show a short example I used when testing this whole process. I simply read all the images from a directory, thehn bind those results to a Repeater Control. First the code to read the images from a directory csharp protected void Page_Load(object sender, EventArgs e) { //create a new IList for holding the image names //<cref=http://msdn.microsoft.com/en-us/library/5y536ey6.aspx</cref> IList<FileInfo> fileList = new List<FileInfo>(); //create a filter so we only get back image files string fileExt = "*.jpg,*.png,*.gif";
//loop through all the items in our "filter" foreach (string ext in fileExt.Split(',')) { //array of file information FileInfo[] files = new DirectoryInfo(this.Server.MapPath("~/images/tagz")).GetFiles(ext);
//loop through each file found foreach (FileInfo file in files) { //add it to our list fileList.Add(file); } }
//bind our repeater this.Repeater1.DataSource = fileList; this.Repeater1.DataBind(); }
Then when I set up my Repeater it looks like this HTML <asp:Repeater ID="Repeater1" runat="server"> <ItemTemplate> <div> <asp:Image ID="Image2" runat="server" ImageUrl='<%# Eval("Name", "ImageThumbnail.ashx?img=images/tagz/{0}&sz=77") %>' /> </div> </ItemTemplate> </asp:Repeater>
There you have it! Create image thumbnails on the fly using an HttpHandler. Of course the path to your images and such will have to be modified, but that is how you work with images with http handler and requests. I hope you not only enjoyed reading this, but found it informative and useful. Happy Coding!
| |
|
|
|
|
|
|
|
26 May, 2008 - 10:23 PM
|
Today we will be talking about manipulating images with C#, using the native .Net Framework, no 3rd party controls whatsoever. Well isn't that one of the selling points of the Framework is that we can write our own components/controls? One thing that I have noticed throughout my career is that working with graphics scares many new and intermediate programmers, and I'm here to show that with the proper .Net Namespaces you can make working with images look like cake work. We will be working exclusively with the System.Drawing Namespace, which gives us access to GDI+. To demonstrate what can be done with this Namespace I have created a small class file, called ImageUtilities, where I can crop an image, resize an image, write text watermarks on an image, all at run-time. Lets take a look at this class; With all classes you need reference to the proper Namespaces, in this class we will use csharp using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; using System.Web; using System.Drawing.Imaging; using System.IO; using RLM.Core.Components;
This class has some property variables, 1 Global (Class Level) variable and 3 properties. First the variables & constants csharp /// <summary> /// variable to hold the image's format type /// </summary> private ImageFormat _formatType = ImageFormat.Gif;
/// <summary> /// mime text property variable /// </summary> private string _mimeText;
/// <summary> /// PercentOfOroginal property variable /// </summary> private float _percent;
/// <summary> /// name of the image we're working with /// </summary> private string _image;
/// <summary> /// font to be used when writing text /// </summary> private const string IMAGE_FONT = "Comic Sanf-Serif";
Now for the object's properties: - MimeType: The MIME type of the current image
- ImageName: Name of the image we're manipulating
- PercentOfOriginal: What percent of the original will the new size be
Now for the property code csharp //// <summary> /// property to hold the mime type of this file /// </summary> public string MimeText { get { return _mimeText; } set { _mimeText = value; } }
/// <summary> /// name of the image we're manipulating /// </summary> public string ImageName { get { return _image; } set { _image = value; } }
/// <summary> /// for resizing, what percent are we changing; 75 percent of original /// </summary> public float PercentOfOriginal { get { return _percent; } set { _percent = value; } }
Now we get to jump right into working with images, a kind of baptism by fire situation. Don't worry, you'll do fine. First order of operation is to write a watermark onto an image. I would like to send special thanks to Martyr2 for his solution of changing the opacity of the watermark text. The process of watermarking is a 2 part process in this class, first method creates the image and Graphics object, while the 2nd takes care of writing the watermark for you. First we will look at part one of this functionality csharp /// <summary> /// method for getting the display image and write the watermark on it /// </summary> /// <returns></returns> private Image GetDisplayImage(Image img, HttpContext context) { //get image t be written on Bitmap bmp = new Bitmap(img);
//create a graphics object from the image Graphics gfx = Graphics.FromImage(bmp);
//set smooting mode gfx.SmoothingMode = SmoothingMode.AntiAlias;
//Write your text. writeWaterMark(gfx, 75, 25, new Font(IMAGE_FONT, 17, FontStyle.Bold, GraphicsUnit.Pixel), "Sample from AngelzDesigns.com"); writeWaterMark(gfx, 75, 125, new Font(IMAGE_FONT, 17, FontStyle.Bold, GraphicsUnit.Pixel), "Image is copyright protected " + System.DateTime.Now.Year); //Save the new image to the current output stream. bmp.Save(context.Response.OutputStream, this._formatType);
//Clean house. gfx.Dispose();
//return the image return bmp;
}
Now for writing the semi-transparent watermark csharp // Takes a graphics object, a font object for our text, and the text we want to write. // Then writes it to the handle as a watermark private void writeWaterMark(Graphics graphicsHandle, int x, int y, Font ourFont, String text) { StringFormat strFormatter = new StringFormat(); SolidBrush transBrush = new SolidBrush(Color.FromArgb(90, 133, 72, 77));
// Drawstring the transparent text to the Graphics context at x,y position. graphicsHandle.DrawString(text, ourFont, transBrush, new PointF(x, y), strFormatter);
}
Next in our class is the ability to change the opacity at run-time. We will accomplish this by introducing you to the ColorMatrix Class and the ImageAttributes Class of the System.Drawing.Imaging Namespace. So now lets look at hoe we combine all these classes to change the opacity of an image csharp /// <summary> /// method for changing the opacity of an image /// </summary> /// <param name="image">image to set opacity on</param> /// <param name="opacity">percentage of opacity</param> /// <returns></returns> public Image SetImageOpacity(Image image, float opacity) { try { //create a Bitmap the size of the image provided Bitmap bmp = new Bitmap(image.Width, image.Height);
//create a graphics object from the image Graphics gfx = Graphics.FromImage(bmp);
//create a color matrix object ColorMatrix matrix = new ColorMatrix();
//set the opacity matrix.Matrix33 = opacity;
//create image attributes ImageAttributes attributes = new ImageAttributes();
//set the color(opacity) of the image attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
//now draw the image gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); gfx.Dispose(); return bmp; } catch (Exception ex) { MessageBox.Show(ex.Message); return null; } }
Next on this gravy train through Image-Ville is a look at resizing an image at run-time. Here we will accept a percentage amount (Say the user wants to resize the image to 75% of the original, we would then pass 75 as the value). We will them retrieve the original dimensions of the image (width & height) and multiply both by the percentage (.75 in our example) to get a height/width combinations that in proportion to the original csharp /// <summary> /// method for resizing an image /// </summary> /// <param name="img">the image to resize</param> /// <param name="percentage">Percentage of change (i.e for 105% of the original provide 105)</param> /// <returns></returns> public Image Resize(Image img, HttpContext context) { try { //get the height and width of the image int originalW = img.Width; int originalH = img.Height;
//get the new size based on the percentage change int resizedW = (int)(originalW * _percent); int resizedH = (int)(originalH * _percent);
//create a new Bitmap the size of the new image Bitmap bmp = new Bitmap(resizedW, resizedH); //create a new graphic from the Bitmap Graphics graphic = Graphics.FromImage((Image)bmp); graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; //draw the newly resized image graphic.DrawImage(img, 0, 0, resizedW, resizedH); //dispose and free up the resources graphic.Dispose(); //return the image bmp.Save(context.Response.OutputStream, ImageFormat.Gif);
return bmp; } catch (Exception ex) { return null; } }
Our final stop through the Wonderful World Of Image Manipulation will be cropping an image. With this method you pass it the name of the image we're cropping, the height & width of the newly cropped image and the x/y coordinates and it will return a cropped image for you csharp /// <summary> /// method for cropping an image /// </summary> /// <param name="img">image to crop</param> /// <param name="width">width of the cropped image</param> /// <param name="height">height of the cropped image</param> /// <param name="x">where on x axis to start</param> /// <param name="y">where on y axis to start</param> /// <param name="context">HttpContext we're working within</param> /// <returns></returns> public Image Crop(string img, int width, int height, int x, int y, HttpContext context) { try { //create a new image Image image = Image.FromFile(img); //create a new Bitmap the size of the image Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
//set the Bitmap's resolution bmp.SetResolution(80, 60);
//create a graphics object from the Bitmap Graphics gfx = Graphics.FromImage(bmp);
//set smooting mode to anti alias gfx.SmoothingMode = SmoothingMode.AntiAlias;
//set the interpolation mode gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
//set the offset mode gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
//draw the new image gfx.DrawImage(image, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
bmp.Save(context.Response.OutputStream, ImageFormat.Gif);
return bmp; } catch (Exception ex) { return null; } }
And that brings us to the end of this little stroll together. Keep an eye out for more on image manipulation, image manipulation using HttpHandler that we will create. Thanks for reading
| |
|
|
|
|
|
|
|
23 May, 2008 - 05:08 AM
|
I guess before you can show someone how to create and consume a Web Service, you need to ensure they know and understand what a Web Service actually is. The following is the easiest, simplest definition I've been able to come up for "What is a web service": What is a Web Service you say? Well a Web Service is very general model for building applications that can be implemented for any operating system that supports communication over the web. To some this may sound a lot like a Web Site, but that is not the case, there are many differences between the two. Here are the main differences between a Web Service and a Web Site: - Web Site has an interface - Web Service has no interface
- Web Site is designed to interact with people - Web Service is designed to interact with other applications
- Web Site is designed to work with web browser clients - Web Service is designed to work with any type of client or device
So as you can see, a Web Service and a Web Application have almost the same role, they just go about fulfilling that role in vastly different ways. A Web Service uses HTTP (Hypertext Transfer Protocol) and SOAP (Simple Object Access Protocol) to transfer data to and from the clients. Data sent to and from the Web Service is rendered into XML so the Web Service can read it, then it is sent back to the silent, which then render the returned XML into the format it was expecting. First, lets take a look at creating a simple Web Service. To do this, open Visual Studio, once it loads click File > New Website, when the New Project Dialog opens, select Web Service from the list of available projects, then for Location select either HTTP or File System (your own IIS), and lastly for Language select C#. When the project is created it creates a Service.amsx and Service.cs file, you can either rename these, or delete and add new ones with the name of SampleService asmx and SampleService.cs.Now double-click on SampleService.cs to open the code file, then make sure you have the following references at the top of your class: CODE using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Data.SqlClient; using System.Data; using System.Configuration;
If all the references aren't there, add the ones that are missing. Next, you will notice the first 2 lines are out of the ordinary, if you've never created a Web Service these two lines are downright weird:
[WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
Heres whats going on here, line 1 declares the Web Service's Namespace, and you might now be wondering Well whats a namespace? Well luckily theres an answer to that: Tempuri.Org defines a Web Service Namespace as: Each XML Web Service needs a unique namespace in order for client applications to distinguish it from other services on the Web. By default, ASP.Net Web Services use http://tempuri.org/ for this purpose. While this suitable for XML Web Services under development, published services should use a unique, permanent namespace.
Your XML Web Service should be identified by a namespace that you control. For example, you can use your company's Internet domain name as part of the namespace. Although many namespaces look like URLs, they need not point to actual resources on the Web. The next line of the first section of the Web Service uses the WebServiceBinding Method to create the Web Service's version of an Interface. After those 2 lines then you have your Initializer, which is, of course, the same as any other class. Here you can instantiate any objects you need used in each instance of the service: CODE public SampleService () {
//Uncomment the following line if using designed components //InitializeComponent(); }
Nothing new there, now we get to jump into the heart of a Web Service, which is, of course, to make it do something, to perform some service. When you create your methods, if you want them to be visible from the client thats consuming the service, you have to add the [WebMethod()] Attribute to it. This tells the service that its ok to expose that method to the client which is consuming it. Since this is just a simple, basic Web Service it only has a single method, just to show you what can be done with a Web Service. Since this service is communicating with a Sql Database, it needs access to the System.Data.SqlClient Namespace. There are other Namespaces the service will use, we listed them above, but lets take a closer look at them: Since the is an example for a beginner with Web Services, our sample service has but a single method in it, GetAllUserInfo. This method is designed to: - Query a SQL Server
- Retrieve all the information for all users in the system
- Populate a DataSet using a SqlDataAdapter
- Pass the DataSet back to the client.
Now lets take a look at the code for this method: CODE /// <summary> /// Here we're going to create a [WebMethod] that /// can be called from an aspx page, then return /// a populated DataSet to the calling aspx page /// </summary> /// <returns>A dataset popululated with the Members informaiopn</returns> [WebMethod] public DataSet GetAllUserInfo() { //Build the SqlCilent Objects we need SqlConnection conn = new SqlConnection(Utlilties.GetConnectionString("WebService_Conn")); SqlCommand cmd = new SqlCommand(); ///SqlDataAdapter to populate our DataSet SqlDataAdapter adapter = new SqlDataAdapter(); ///DataSet to hold the users information DataSet dsInfo = new DataSet(); ///String to hold our stored procedure string query = "RetrieveUserInfo"; ///try...catch block to handle any unhandeled exceptions try { //set our SqlCommands Objects cmd.CommandText = query; cmd.CommandType = CommandType.StoredProcedure; //tell it its a Stored Procedure we're executing //if using inline SQL change the CommandType to Text //cmd.CommandType = CommandType.Text; //set its connection property cmd.Connection = conn;
//now handle the connection state ///of our SqlConnection Object /// Utlilties.HandleConnectionState(conn); //set the SelectCommand Property ///of our SqlDataAdapter Object adapter.SelectCommand = cmd; //now we fill our DataSet ///using the Fill Method of ///the SqlDataAdapter adapter.Fill(dsInfo, "Members"); //return the DataSet to the calling aspx page return dsInfo; } catch (Exception ex) { System.Web.HttpContext.Current.Response.Write(ex.Message); return null; } finally { ///put everyting in the finally section ///of the try...catch block you want executed ///whether theres an exception or not, in this ///case we want to close the connection no ///matter what happens ///close the connection /// Utlilties.HandleConnectionState(conn); } }
This operates as explained. It opens a connection to our database, retrieves all the user information from the users table, then populates a Dataset ans returns the DataSet to the client. Notice the [WebMethod()] attribute at the start of the method, this says that any client that consumes this Web Service will have access to that method, and the data it returns. Believe it or not, our Web Service is complete. Now with a Web Service in a production environment will have much more meat on its bones, but for our demonstration, this is really all we need to show how a Web Service works. Next question people ask is "Ok, we have this service out there on our server, how do we access it and use it?". Well thats a good question, to use the Web Service we just created you need a consumer, a client that will connect to the service and gather the data. In this example we will create an ASP.Net Web Application that will consume our Web Service, then display the returned data in a GridView Control. So, in your Solution Explorer window, right-click on the very top node, the solution name, then select Add > New Project. Once the New Project Dialog opens, you will this time select ASP.Net Web Site as the project type, once again either HTTP or File System for the Location and C# for the Language. When the project is created is automatically adds a Default.aspx, and Default.aspx.cs. It's the CS file we will be doing the programming in. You always want to keep your presentation separate from your logic, thats why Microsoft offers both files for a single page in .Net. Since this is just a sample, open Default.aspx in Design Mode, add a table to the page, then a GridView to the page. The GridView is what we'll use to display the data returned from our Web Service. You are now finished designing our ASPX page for consuming our Web Service. Now open Default.aspx.cs, and make sure you have the following references at the top of your class: CODE using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls;
Those are the only references you will need for this example. Now we need to add a reference to the Web Service we just created, to do this: - Right-click on the project name
- Select Add Web Reference
- Once the dialog box opens select Web Services in this solution
- Once it finds your service, click on its name
- Wait for it to connect to the Web Service (when this happens the TextBox in the right-hand side of the dialog will be populated with the word localhost
- Click the Add Reference button
NOTE: Before clicking the Add Reference button I renamed my from localhost to Sample Now we have a reference to our Web Service and can starting using it. In our ASPX page we have a single method, BindGrid(), and this method will: - Create a reference to our Web Service
- Create a new DataSet
- Set our DataSet to the GetAllUserInfo method in our Web Service (remember, it returns a populated DataSet)
- Bind the returned DataSet to our GridView
The code for this method is: CODE private void BindGrid() { //create our DataSet to hold the member information returned DataSet dsMembers = new DataSet(); //create our WebService object WebServiceConsumer.Sample.SampleService sample = new WebServiceConsumer.Sample.SampleService(); //set our DataSet to the GetAllUsers Method of our web service dsMembers = sample.GetAllUserInfo(); //now we need to set some properties for our data grid gvMembers.AutoGenerateColumns = true; gvMembers.DataSource = dsMembers.Tables["Members"].DefaultView; gvMembers.DataMember = "UserID"; gvMembers.DataBind(); }
Simple enough isn't it? Now to use this, we will call this method from our Page_Load Event in our page, and that looks like this: CODE protected void Page_Load(object sender, EventArgs e) { BindGrid(); }
Believe it or not, thats it, thats all the code required to consume our Web Service and display the returned data. The one difference in our BindGrid method is this: WebServiceConsumer.Sample.SampleService sample = new WebServiceConsumer.Sample.SampleService(); That is where we create the reference to our Web Service, then we can use sample.WhateverMethodIsThere for utilizing the methods in the Web Service, instead of typing the long name out. Thank you for reading, and I hope you found this helpful
| |
|
|
|
|
|
|
|
23 May, 2008 - 04:34 AM
|
Recently I discovered the WMI (Windows Management Instrumentation) and was stunned at what it can do. Granted, the discovery was completely by accident, but I found it none the less. The WMI can mystify a lot of developers, especially new ones, so granted I was a little nervous and leery when I dove further into it, but what I found is that it can be an invaluable tool. I jumped into learning the System.Management Namespace (which is where the WMI resides by the way) and discovered that WMI can save a developer tons of research time, clock cycles (as it is faster than other methods) and hair (from pulling it out looking for a solution). When developing Windows applications, developers often need information a system, either local or remote, that although commonplace, can be very tough to get. There is using the remote registry, but I myself do not allow remote registry access as do many network admins. WMI is usually wide open on networks, assuming you have the privileges necessary to query it, just as it is with remote registry querying/editing. There is another reason WMI appeals to so many developers nowadays, its called WQL (Windows Query Language). WQL allows us a developers to query WMI providers using a SQL-like query language. If you know the provider classes and the fields available, then you can get the info very easily. Lets say, for instance, that you wanted to see the capacity, used space and free space available on a CD-ROM, you WQL query would look like: "select * from Win32_LogicalDisk WHERE DriveType = 5" You can then take that query, plug it into a ManagementObjectSearcher (a member of the System.Management Namespace), then use that to retrieve that particular information. In my example I populate the returned data into a Generic Dictionary<string,string> list, you may chose to do otherwise. But to retrieve the information I spoke about earlier, here is how you would find that information about the CD-Row: CODE public Dictionary<string, string> GetDriveInfo() { //dictionary object to hold the values Dictionary<string, string> driveInfo = new Dictionary<string, string>(); //create our WMI searcher ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"select * from Win32_LogicalDisk WHERE DriveType = 5"); //now loop through all the item found with the query foreach (ManagementObject obj in searcher.Get()) { //create the used space by subtracting the size from the free space double used = (double)obj["Size"] - (double)obj["FreeSpace"]; //add all the items to the collection driveInfo.Add("FreeSpace", obj["FreeSpace"].ToString()); driveInfo.Add("Capacity", obj["Capacity"].ToString()); driveInfo.Add("UsedSpace", used.ToString()); } //return the info return driveInfo; }
Notice how simple that was, and how ordinary it looks, it almost looks like you're querying a Database, but in fact you're querying a computer, either the system the application is running on, or a remote machine you have access to. MSDN has a great writeup on WQL, what the DriveType values are you see me using in my queries, so don't let this scare you off, in the long run it will be quite the time saver when developing applications. Lets say you need to know how much free space is available on a network drive, before WMI and WQL you would have to rely on trying a remote registry query (testy at best, and it has to be open on the machine), but with WMI its a simple WQL query then a search. The WQL Query for retrieving all network drives is: "select name, FreeSpace from win32_logicaldisk where drivetype=4" Notice I altered this query, unlike the first one I showed, in this one I only want to return the name of the network drive and the freespace it contains, I seen no need to return all the information if all I really wanted was 2 pieces. That would be the equivalent of "SELECT * FROM Table_Name" when all you needed was the record ID's. Once again we will plug this query into a ManagementObjectSearcher, this time using a SelectQuery, another member of WQL and the System.Management Namespace: In this example I chose to populate a HashTable with the data returned, you, as with before, may chose to do it in a different fashion: CODE public Hashtable ReadFreeSpaceOnNetworkDrives() { //create Hashtable instance to hold our info Hashtable driveInfo = new Hashtable(); //query the win32_logicaldisk for type 4 (Network drive) SelectQuery query = new SelectQuery("select name, FreeSpace from win32_logicaldisk where drivetype=4"); //execute the query using WMI ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); //loop through each drive found foreach (ManagementObject drive in searcher.Get()) { //add the name & freespace to our hashtable driveInfo.Add("Drive", drive["name"]); driveInfo.Add("Space", drive["FreeSpace"]); } return driveInfo; }
So, as you can see the WMI can be an invaluable tool to learn, and in my opinion its worth the time to learn. WMI can save you time, it definately, as shown in the 2 methods, much simpler than trying a remote registry query, and I think as more and more developers discover and learn how to use WMI it will definately grow.
| |
|
|
|
|
|
|
|
22 May, 2008 - 03:04 PM
|
IntroductionThe following article will provide recently found issues discovered when planning a system separation using Merge Replication using Microsoft SQL 2000 Database Server. These issues (or pitfalls) were discovered first-hand in a real world environment at the company I work for when we were doing a monthly release of our in-house software, while getting ready for a complete System Separation using Merge Replication. The resolutions offered in this article have been tested and are known to work. BackgroundThe company I work for made a decision that in order to keep up with the continuing growth of the company and our ever expanding customer base the best way to improve the performance of both our web presence and our in-house applications was to do a complete System Separation by co-locating our database servers off-site, the cut down on the use of bandwidth and increase the overall performance of our websites. The decision was made to move all the web data off-site and use Merge Replication in SQL 2000 to keep the in-house data and the web data synchronized, since the in-house applications needed use of the web data as well. The databases, and the required objects within the database (stored procedures, tables, user-defined functions, triggers, etc) were marked for replication and all was moving ahead smoothly. When we create our database scripts, whether it be triggers, alter table scripts, or stored procedures, we employ the use of an in-house created version control header to prevent old scripts from being promoted to production. In the header template the script it searches the sysobjects System Table for a procedure with that name. If the procedure is found, it is dropped then recreated, incrementing the version of the script, otherwise it simply creates the stored procedure as normal. This is when the first pitfall was recognized. If a stored procedure has been marked for replication using Merge Replication you cannot simply drop the procedure and re-create it, you must do the search (as normal for us), if the procedure is found then the script alters the procedure, if it isn't found then it is created (a blank procedure with the parameter list) then it is altered to add the "meat" of the procedure. This was a simple enough issue and resolution, causing a minor setback, but nothing we couldn't recover from in a small amount of time. The next pitfall, discovered by myself during the promotion and build of a monthly release of an in-house application, wasn't quite as simple to fix, and could have caused a huge problem if it had not been discovered prior to the system separation. Had that happened, if this situation had been encountered (we'll get to the "situation", or sequence of events momentarily) while doing one of the monthly builds for anyone of the in-house application after the seperation it would have posed serious problems for my company Scenario:While making updates for my application for the next monthly release, I created and ran an alter table script because I needed to add some additional columns to a table. I created the script and ran it on the dev server, a mirror image of production, or so I thought, and it ran fine, no problems at all, so I continued with my tasks for the monthly release. It wasn't until it was time to promote the current monthly release to the QA Department that the pitfall was discovered. While running one of the Alter Table scripts I created, the following error was displayed: Version: 01.00 of: PAT dbo.*Alter_Table_Script.pat (1 row(s) affected) Server: Msg 4931, Level 16, State 1, Line 3 Cannot add columns to table * 'Table_Name' because it is being published for merge replication. - Aborting!!!
Well as you can imagine when I seen this I had a feeling this wasn't good news. It was 9PM at night and I knew there was nothing I could do until morning when the DBA arrive at work. The next morning:So 7:00 AM rolls around the next day and I am already at work with the DBA trying to find out what went wrong, and what kind of impact this had on our system separation project. After a little research he thought the system separation was dead, unless we could upgrade to SQL 2005 and in a hurry, as the separation was mere weeks away. There was some fierce searching going on in the office, Google was being taxed, online SQL 2000 reference sites, in-house SQL Library (which is actually quite extensive), there were 3 of us desperately looking for a resolution to our problem. The first solution turned out to be not so reliable. When a database is marked for replication, then subsequent tables are marked, SQL creates a corresponding table for the marked table, the tables are named conflict_DBName_TableName, so I started building a query based on that, until we realized that SQL 2000 doesn't clean up after itself, when a table is no longer marked for Merge Replication that table isn't deleted, thus offering the possibility of "false positives" when the query is ran. So of course, this solution was scrapped. Solution:When a database is marked for Merge Replication SQL 2000 creates a new database, aptly named distribution, inside this database is a table named "MSArticles". It is in this table that all the names of all objects that have been marked for Merge Replication are stored, along with the object type.Then there is a system stored procedure names sp_repladdcolumn but of course this stored procedure can only be ran on tables that have been marked for replication, it will fail otherwise. This gave me what I needed, what I had to do was first check and see if the database has been marked for Merge Replication, as if its not then the search of distribution.dbo.MSArticles will cause an error, thus failing all together. Taking this all into consideration, I wrote the below script that did everything I needed it to do, tested it, then released it to the other developers on the team. * Denotes table name and script name changedUsing the codeThe script I came up with below will have certain information missing, information that is specific to our Version Control Header, and propietary to the company I work for, I will however show the script part that actually: 1. Checks if the database has been marked for Merge Replication 2. Check if the table actually exists (just a double check I like to perform, I don't like surprises) 3. Checks to see if the table has been marked for merge replication 4. Alter the table accordingly CODE /* Below is the script used to check required elements so that an Alter Table script can be created and ran on a SQL 2000 database that has been marked for Merge Replication. First check if the database has been marked for replication. If it hasnt and you search distribution.dbo.MSarticles you will an "Invalid Object Name" error */ IF EXISTS(SELECT * FROM master..sysdatabases WHERE name='distribution') BEGIN /* Next make sure table exists in the database*/ IF EXISTS (SELECT *
| |