|
|
by Viper
5. November 2009 06:19
When we are creating a web site, one of the main goal we all have is that out site should be listed on first page of search engines like Google, Bing, Yahoo, Baidu etc. As we all know that in SEO world, one of the first thing we all look for in the page is meta tags in header of the page. In the past there was no direct way to set the meta tags on a page programatically when developing ASP.Net web site. We all used the work around of adding metaelements in header element of the page. You can read my previous post Adding meta tags to asp.net page dynamically about that technique. With ASP.Net 4.0 microsoft has introduced following two properties on that allow you to set the meta tags on a page.
- MetaDescription
- MetaKeywords
Following code snippet shows how it is used in your code.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
SetMetaTags();
}
private void SetMetaTags()
{
Title = "Hello Meta";
MetaDescription = "This is description of my ASP.Net 4.0 page.";
MetaKeywords = "ASP.Net,.Net4.0,Meta";
}
}
And it works. You can see from the source of the page as shown below.
<head>
<title>Hello Meta</title>
<meta name="description" content="This is description of my ASP.Net 4.0 page." />
<meta name="keywords" content="ASP.Net,.Net4.0,Meta" />
</head>
by Viper
20. July 2009 15:06
Download Sample Project
For one of my current project, I have been using ASP.Net AJAX to make async request into my ASP.Net to get some time related data. First, I am not a big fab of ASP.Net AJAX implementation. I will not go into debate on why. There are plenty of discussions on this topic. I will just spare myself from it. Second, the application was already using jQuery for other javascript related implementation. I was like, if we are already using jQuery why have an overhead of introducing Ajax tool kit. So I started porting the implementation to use jQuery. Through this series of posts, I will describe how you can use jQuery to make AJAX calls in ASP.Net applications. Well, the client side javascript can be used in any browser. So other than the server side implementation, there is no nothing specific to ASP.Net per se.
The sample project for these articles is a time synchronization service. The idea is that I want to display clock on the client machine that will display server time. Well you can say there is no big deal with that implementation. On page load, get the server time. Save in some client side variable and run one second timer on it. Well, that works for most part. There are situations where clients are behind really slow connections that can cause of lot latency in request and response. So in those cases, by the time your response gets to the client side, the server time that you returned to client is already behind by few seconds. For applications that has users who depend very heavily on this server time, this latency of few seconds can be very critical. In this first post I am not going to go into details of algorithm that I implemented to reduce this latency adjustment over time. This first sample does a very simple task. It sends asynchronous request to server every 10 seconds. The server returns its time and then client uses that to display clock.
Server Side Implementation
I have a class ClockData that has DataContract attribute set on it. You can pretty much figure out that I am planning on converting this service to WCF service and use the framework facilities to serialize and de-serialize data as well. So I am populating this class with three pieces of data (server time, latency and a cookie) and then using DataContractJsonSerializer class to serialize the data into JSON format and sending it to client.
private void SerializeServerClockData(ClockData data, Stream strm)
{
var spSer =
new DataContractJsonSerializer(typeof(ClockData));
spSer.WriteObject(strm, data);
}
void SendResponse()
{
long ms = (long)(_serverTime - new DateTime(1970, 1, 1)).TotalMilliseconds;
var clockData = new ClockData()
{ServerTime = ms.ToString(), Latency = _latency, ResponseKey = Guid.NewGuid().ToString("N")};
Response.ContentType = "text/plain";
Response.Expires = -1;
Response.CacheControl = "no-cache";
SerializeServerClockData(clockData, Response.OutputStream);
Response.End();
}
From the code snippet above, you can see how plain and simple server side implementation is for this first sample. This will get little complicated as I get more into the actual algorithm of calculation of latency reduction.
Client Side Implementation
Since we are going to be using jQuery to make Ajax call, so we will need to include reference to jQuery javascript file. For this sample, I am going to show the AJAX request you can send using jQuery. The library has method named .getJSON that you can call to send the request. You can set the URL where request is to be sent, set the parameters that needs to be passed with request and set the callback function that should be called when request completes. It is that simple. Here is the implementation from the sample.
function getServerTime() {
cTime = firstRequest ? -1 : curTime.getTime();
$.getJSON(clockServiceUrl, { clientTime: cTime, requestKey: respKey }, gotServerTime);
}
function gotServerTime(data) {
firstRequest = false;
latency = data.Latency;
curTime = new Date(parseInt(data.ServerTime));
if (!clockTicking) createClockTimer();
createServiceTimer(defaultServiceTimer);
}
function clockTick() {
clockTicking = true;
curTime.setTime(curTime.getTime() + 1000);
elClockDisplay.text(curTime.toString());
if (latency == -1)
{ elLatencyDisplay.text(""); }
else
{elLatencyDisplay.text(latency + " ms");}
}
$(function() {
elClockDisplay = $('#clockDisplay');
elLatencyDisplay = $('#latencyDisplay');
getServerTime();
});
In subsequent posts I will discuss how you can control the request little bit more instead of using .getJSON to use default settings.
by Viper
7. July 2009 14:35
Download Sample Project
This was a question was asked by one of my site visitors, Mike. Following is the text of the question:
This is a similar question to one you have already answered in formatting Grid Views. However there are 2 main differences. First: I want to change the value of a column (not the format) in any row if the row preceding it has a certain value in the same column.
This question translates to How do you change value of a data grid column based on values of previous row(s). I generalized this question to cover all previous rows and not just the preceding row. Answer to all such questions relies on handling events like RowDataBound or RowCreated events. When a data grid or grid view renders, RowDataBound fires when row is being data bound and then RowCreated is fired after it has been data bound and row has been created. So depending on at what stage of rendering you want to change behavior of a row, you will subscribe either of these events. In the sample project, I am subscribing to RowDataBound event.
Next step is to access values from previous rows. Here you have choice. One, you can keep some local vaiable that stores values from previous row(s) and then use them in current row event handling. Two, you can access the previous GridRow based on index. In this sample i will discuss the approach of accessing previous row based on index and then extracting values from certain cells.
In RowDataBound event handler, GridViewRowEventArgs provides you access to DataItem associated with current row only. You do not have access to DataItem associated with previous rows. But at this point, previous rows have been prepared for rendering. You have access to all the cell values associated with previous row. You can access GridRow object of previous rows and extract text from cells that you are interested in. In the sample project, I am accessing ListPrice from fourth column and then displaying it in current row along with price associated with current row. Well, this does not sound like something that is very interesting or useful. But it serves the purpose of demonstrating you will accomplish the task.
Here is the code snippet from sample project.
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
double price = -1.0;
double prevPrice = -1.0 ;
// Access the previous row.
if (e.Row.RowIndex != 0)
{
GridViewRow prevRow = this.productsGrid.Rows[e.Row.RowIndex - 1];
if (null != prevRow &&
prevRow.RowType == DataControlRowType.DataRow)
{
double.TryParse(prevRow.Cells[3].Text, out prevPrice);
}
}
var thisRowData = e.Row.DataItem as DataRowView;
if (!Convert.IsDBNull(thisRowData["ListPrice"]))
{
double.TryParse(thisRowData["ListPrice"].ToString(), out price);
}
var ctrl = e.Row.FindControl("prevPriceLabel") as Label;
if (null != ctrl)
{
ctrl.Text = string.Format("{0} - {1}", prevPrice, price);
}
}
}
The attached sample project is a VS2010 project. There is no VS2010 or .Net4.0 implementation in the project. So if you are using VS2008 or prior, you should be able to copy the implementation files into your own project.
Feel free to send me any request for any other grid view implementation you would like to be answered or implemented.
by Viper
20. June 2009 20:11
Download SpamTrainer Binaries
Download SpamTrainer Source
As more and more people are tweeting, spam is growing with it as well. Every time I search for some topic, almost half of the messages seem to fall in one of the following categories:
- Somebody is trying to sell something
- Somebody is posting links to get you affiliate web sites to make some money
- Job agencies are posting jobs
- .... and more
This week I decided to use Bayesian spam filter, that is used in most email servers to filter spam, on twitter messages. While searching around I found Bayesian Spam Filter for C#. That gave a good starting point. Without making any changes or training with any additional corpus, I was able to get very good filtering results. I observed close to 90% spam detection. I studied the messages that fell through the cracks and also studies false positives. Based on the observations I figured that issue is very limited context of 140 characters in twitter. A lot of good and spam twitter messages look pretty much the same. So the key to improving spam filtering results was to train the filter with twitter messages and not use just rely on corpus taken from emails or things like that. So I decided to build an application that I could use to generate corpus that is classified as spam and good twitter messages.
How does it work
-
Start the application.
- Enter a search term and click on "More Data" button.
- Application will do initial classification of messages. All spam messages are displayed in Orange or light blue color.
- Double on any message to change its classification.

- Once you are satisfied with the results, click on "Accept" button and results are saved in appropriate good and spam files.
- You can load the new corpus results by clicking on "Reload Corpus".
Spam Filter Service
I have created a service that you can use to classify your text if you do not want to build one of your own. Following link provides
more details about the service.
Spam Filter Service
by Viper
16. June 2009 19:15
I am working on adding new features to Marketweet - Twitter Autofollow application. The new feature will show some details about followers of an account. And one of the details is showing image associated with user's profile. To get that to work, I have developed an image service that downloads the user images in the background. This is done using HttpWebRequest object to send request to image URL that is set as user's profile image. Following code shows you how you can download an image from a web site programatically using HttpWebRequest. Also notice how ContentType property of HttpWebResponse is utilized to make sure that response from the specified URL is of type type/xxxx.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DownloadImage(113467,
@"http://s3.amazonaws.com/twitter_production/profile_images/214863919/logo_normal.jpg");
}
static void DownloadImage(int userId, string url)
{
HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;
HttpWebResponse resp = webRequest.GetResponse() as HttpWebResponse;
if(resp.StatusCode == HttpStatusCode.OK)
{
if (resp.ContentType.Contains("image/"))
{
int idx = resp.ContentType.IndexOf("/");
string fileName = string.Format("{0}.{1}",
userId, resp.ContentType.Substring(idx + 1));
byte[] imageContent = ProcessImageStream(resp);
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
fs.Write(imageContent, 0, imageContent.Length);
fs.Close();
}
}
}
private static byte[] ProcessImageStream(HttpWebResponse resp)
{
Int64 iContentLength = resp.ContentLength;
byte[] streamContent;
MemoryStream memStream = new MemoryStream();
const int BUFFER_SIZE = 4096;
int iRead = 0;
int idx = 0;
Int64 iSize = 0;
memStream.SetLength(BUFFER_SIZE);
try
{
using (memStream)
{
while (true)
{
iRead = 0;
byte[] respBuffer = new byte[BUFFER_SIZE];
iRead = resp.GetResponseStream().Read(respBuffer, 0, BUFFER_SIZE);
if (iRead == 0)
{break;}
iSize += iRead;
memStream.SetLength(iSize);
memStream.Write(respBuffer, 0, iRead);
idx += iRead;
}
streamContent = memStream.ToArray();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return streamContent;
}
}
}
Discussion
After this entry was posted, Mark pointed out in his comment that it could be achieved in 2 lines of code. I will post those two lines of code here.
Dim r As New System.Net.WebClient
r.DownloadFile("http://http://aspnetlibrary.com/images/logo.png",
"c:\aspnetlibrary.png")
This approach works perfectly fine if both variables in this method signature are very well known. What this means is that you know that target URL is what it says (that I am an image file of type PNG). Here are some issues that you have to think about when you are building a solution that involves downloading of files (image, multimedia or any kind).
- Lets start with evil that is lurking around these days called Tiny URLs. These started with some good intent but now these have become medium to disguise spam, tricking people into clicking on links that are click advertising, redirecting to questionable sites, key loggers. So if the image URL is like http://tinyurl.com/45fghty, you don't even know what it is. So you really don't know what to save this file as.
- If you don't know what mime type actually is associated with file that is being downloaded.
What you have to rely on is headers that are associated with response. You can see from code snippet how header information is utilized to establish file type and create file name on the fly.
by Viper
15. June 2009 13:41
Some time back I wrote a post on C# API for Amazon Product Advertising Web Service. If you are one of amazon associates who is using their web service to advertise their products to earn some money, then you must be getting emails with following message from Amazon.com.
We wanted to remind you that all Product Advertising API developers will be required to authenticate all calls to the Product Advertising API by August 15, 2009. We noticed that requests with your AWS Access Key ID are not being signed and, while you have more than 60 days until the date on which authentication is required, we are, as a courtesy, sending you this email to remind you of the new authentication requirement. Please remember that calls to the Product Advertising API that are not signed will not be processed after August 15, 2009.
There is nothing to worry about this. It is a very simple change that you will need to make on your end. Amazon has given two options to digitally sign the requests. Either encrypt all requests with HMAC-SHA encryption or use X509Certificate. If you don't have X509Certificate, don't worry about it. Amazon.com is creating one for you if you ask it to. I found this option to use X509Certificate to be the easiest to comply with Amazon.com policy. Here are the steps you will need to use.
- Login into your AWS account.
- Click on Access Identifiers link on Your Account page.
- At the end of the page you will find section for X509.Certificate. Click on Create New option to create your certificate.
- Make sure that you follow the instructions and save the private key and certificate file as the process asks you to.
Now time to make code change. It is simple. Just add one line to your implementation and you are all set.
m_obAmazonService.ClientCertificates.Add(X509Certificate.CreateFromCertFile(X509CertFile));
X509CertFile is full path to where this file is stored. If you are using the API in web application, make sure you specify fully qualified path and your application has read permissions on this file as well. You can this in action here - Winazon.Net
by Viper
12. June 2009 08:31
While working on a clock synchronization service, I had to dig up an old piece of code that I used to round off numbers. For this application I need to round the number to 0 or next 0.5 depending on it proximity to edge. For example if number is 8.001, it gets rounded off to 8.0 and if it is 8.6123 it will be rounded to 8.5. You can argue why not 9 instead of 8.5. Well the logic of the application demands that number is to be rounded down. Here is simple piece of code that will do the trick.
double roundDownNumber = Math.Round(actualNumber * 2.0, 0) / 2.0;
Just simple idea that multiply the number by 2 and round it to ZERO decimal places and then divide by 2.
by Viper
9. June 2009 04:58
While developing Twitter applications, one of the common patterns that used to emerge is that some particular users will post lot of messages in a short time span. And when searching records, I used to end up with multiple messages from one particular user. So for some user interface, I always had to group messages by user posting the message.
Following code shows how easy it is to group records using LINQ. Just to explain the code a little bit, when search is performed for a certain query term using twitter rest api with Tweetsharp, results are returned as list of TwitterSearchStatus objects. The user who posted the message is indicated by FromScreenName property. So this property becomes the key on which grouping is to be performed. Following group statement shows how grouping is done in LINQ statement.
var resultsGrpByUser = from searchResult in searchResults
group searchResult by searchResult.FromUserScreenName
into userMessages
select new { FromUser = userMessages.Key, Messages = userMessages };
Above code uses group statement to create group on user name, and the grouping results
are returned as Dictionary of anonymous objects that have properties named FromUser and Messages. Following code snippet shows the whole implementation of grouping using LINQ.
static Dictionary<string, List<TwitterSearchStatus>> GetPopularTweets()
{
List<TwitterSearchTrend> trends = GetDailyTrends();
if (null == trends ||
trends.Count == 0)
{
return null;
}
// For now only process first trend term.
List<TwitterSearchStatus> searchResults = SearchForTerm(trends[0].Query);
if (searchResults.Count == 0)
{
return null;
}
var resultsGrpByUser = from searchResult in searchResults
group searchResult by searchResult.FromUserScreenName
into userMessages
select new { FromUser = userMessages.Key, Messages = userMessages };
Dictionary<string, List<TwitterSearchStatus>> dict =
new Dictionary<string, List<TwitterSearchStatus>>();
foreach(var userMessage in resultsGrpByUser)
{
Console.WriteLine(userMessage.FromUser);
foreach(var twitterStatus in userMessage.Messages)
{
Console.WriteLine("\t{0}", twitterStatus.Text);
}
dict[userMessage.FromUser] = userMessage.Messages.ToList();
Console.WriteLine("*************");
}
return dict;
}
by Viper
9. June 2009 04:34
In my earlier posts Daily twitter trends and Weekly twitter trends I showed how you can get daily and weekly twitter trends. That api gets you to queries that are being searched for. Next step in the process is to take those queries and get the messages posted related to those queries. Here is a simple method that combines results of trend api with search api to get popular messages on twitter.
static Dictionary<string, List<TwitterSearchStatus>> GetPopularTweets()
{
List<TwitterSearchTrend> trends = GetDailyTrends();
if (null == trends ||
trends.Count == 0)
{
return null;
}
// For now only process first trend term.
List<TwitterSearchStatus> searchResults = SearchForTerm(trends[0].Query);
if (searchResults.Count == 0)
{
return null;
}
var resultsGrpByUser = from searchResult in searchResults
group searchResult by searchResult.FromUserScreenName
into userMessages
select new { FromUser = userMessages.Key, Messages = userMessages };
Dictionary<string, List<TwitterSearchStatus>> dict =
new Dictionary<string, List<TwitterSearchStatus>>();
foreach(var userMessage in resultsGrpByUser)
{
Console.WriteLine(userMessage.FromUser);
foreach(var twitterStatus in userMessage.Messages)
{
Console.WriteLine("\t{0}", twitterStatus.Text);
}
dict[userMessage.FromUser] = userMessage.Messages.ToList();
Console.WriteLine("*************");
}
return dict;
}
by Viper
5. June 2009 04:53
As more and more have started to integrate Twitter API into the applications and allowing user to post messages and do other twitter related tasks, one of the essential step in the work flow is to verify a user's twitter credentials. There are certain tasks you can perform without logging into API. But when it comes to posting messages or pulling a user's data etc., Twitter API wants the user to be authenticated. Here is a code snippet that shows how you can use Twitter API to verify a user's credentials or verify user's login information.
static TwitterUser VerifyTwitterCredentials(string login, string password)
{
IFluentTwitter ft = FluentTwitter.CreateRequest();
ft.AuthenticateAs(login, password);
ft.Accounts().VerifyCredentials().AsJson();
var resp = ft.Request();
TwitterUser tUser = resp.AsUser();
if (null == tUser)
{
var err = resp.AsError();
Console.WriteLine("Twiiter Error: " + err.ErrorMessage);
}
return tUser;
}
When verification fails, you will get a response that will not get converted to TwitterUser object and method will return null object.
by Viper
3. June 2009 14:34
These days Twitter is the thing to do for lot of people. And lot of folks have found ways to leverage this microbloging site to promote things like product sales, real estate etc. Since twitter only allows 140 characters to post a message, pasting a regular URL could take pretty much all the characters and some times the URLs are so big that even 140 characters are not enough. This has made use of TinuUrl and services like this very popular. When you click on one of these tiny urls, you land on real URL behind it. While working on Backyard Tweets application, I had the requirement to actually translate these compressed or shortened URLs into real long urls. The concept behind these tiny urls is very simple. When you submit your actual long url to one of these services, they encode the url and create a compressed version of url and return it to you. When user clicks on this url, the request goes to this url service. Then this service decodes this encoded url back to actual url and send a HTTP status code of 301 to the caller. This code means that the requested resource has been permanently moved to some other location. And this so called other location is the actual url. The value of this other url is set in Location header of HTTP response. You can see all this in following C# code snippet that I used to write a tiny console application.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string tinyUrl = "http://ow.ly/atLJ";
var longUrl = DecodeShortUrl(tinyUrl);
Console.WriteLine("{0} -> {1}", tinyUrl, longUrl);
}
static string DecodeShortUrl(string shortUrl)
{
HttpWebRequest webReq = HttpWebRequest.Create(shortUrl) as HttpWebRequest;
webReq.AllowAutoRedirect = false;
HttpWebResponse webResponse = webReq.GetResponse() as HttpWebResponse;
if (webResponse.StatusCode == HttpStatusCode.MovedPermanently)
{
return webResponse.Headers["Location"];
}
return shortUrl;
}
}
}
Now only thing you need in your real application is a regular expression to extract these compressed urls and feed it to this tiny
method and get back your actual url behind it. The most important part of this code is setting of AllowAutoRedirect property
of HttpWebRequest. If you do not set it, the request will get redirected to actual url.
by Viper
1. June 2009 19:10
Recently I implemented BackYardTweets. Big part
of the site is geo targeting. What that means is that to figure out location of the user visiting the site and getting
longitude and latitude of that location. The implementation uses the following work flow:
- When user visits the site, only information that is available is IP adress assigned to your network connection by
user's internet service provider. The implementation translates that IP address to location including coordinates (longitude and
latitude).
-
After user has logged in, application allows user to change location. User
can pick country, region and city. From these three (some time only 2), application determines geolocation.
Now I will explain how these two steps are performed.
Convert IP Address To Geo Location
Application uses IP to geo location service provided by IP Location tools. A
simple HTTP request to this site's target URL sends xml response that containss all the data that you will need to get location of
site's visitor. Following is sample response.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Ip>74.125.45.100</Ip>
<Status>OK</Status>
<CountryCode>US</CountryCode>
<CountryName>United States</CountryName>
<RegionCode>06</RegionCode>
<RegionName>California</RegionName>
<City>Mountain View</City>
<ZipPostalCode>94043</ZipPostalCode>
<Latitude>37.4192</Latitude>
<Longitude>-122.057</Longitude>
</Response>
Following code snippet shows the implementation that was done in the application to get geo location based on IP
address of site visitor.
public class UserGeoLocator
{
private const string ApiUrl = "http://ipinfodb.com/ip_query.php?ip={0}";
public SiteUser GetUserLocation(string ipAddress)
{
if (string.IsNullOrEmpty(ipAddress))
{
return null;
}
string reqUrl = string.Format(ApiUrl, ipAddress);
HttpWebRequest httpReq = HttpWebRequest.Create(reqUrl) as HttpWebRequest;
try
{
string result = string.Empty;
HttpWebResponse response = httpReq.GetResponse() as HttpWebResponse;
using (var reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
return ProcessResponse(result);
}
catch (Exception ex)
{
throw;
}
}
private SiteUser ProcessResponse(string strResp)
{
StringReader sr = new StringReader(strResp);
XElement respElement = XElement.Load(sr);
string callStatus = (string)respElement.Element("Status");
if (string.Compare(callStatus, "OK", true) != 0)
{
return null;
}
SiteUser user = new SiteUser() {IP = (string) respElement.Element("Ip"),
City = (string) respElement.Element("City"),
Country = (string)respElement.Element("CountryName"),
CountryCode = (string)respElement.Element("CountryCode"),
RegionCode = (string)respElement.Element("RegionCode"),
RegionName = (string)respElement.Element("RegionName"),
PostalCode = (string)respElement.Element("ZipPostalCode"),
Latitude = (decimal)respElement.Element("Latitude"),
Longitude = (decimal)respElement.Element("Longitude")};
return user;
}
}
Geo Location From Address
Application allows user to select Country, Region and City. This needs to
be translated to geo location. Application uses Google's Map API to accomplish the task. For this
you will need to apply for key from Google. Following code snippet is from the application. It takes
address of user as input and translates it to latitude and latitude. Following
code snippet is from class implemented in the application.
public static bool GetGeoLocationFromGoogle(string nearLocation,
out double longitude, out double latitude)
{
bool ret = false;
longitude = latitude = 0d;
string apiKey = ConfigHelper.GooleMapKey;
string reqUrl = string.Format("http://maps.google.com/maps/geo?q={0}&output={1}&key={2}",
HttpUtility.UrlEncode(nearLocation), "csv", apiKey);
WebClient httpClient = new WebClient();
try
{
string response = httpClient.DownloadString(reqUrl);
string[] values = response.Split(",".ToCharArray());
if (values.Length == 4)
{
if (values[0] == "200")
{
latitude = double.Parse(values[2]);
longitude = double.Parse(values[3]);
ret = true;
}
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
return ret;
}
See how it works
Use see all this in action at following link
by Viper
4. May 2009 12:37
Every time somebody says Use WMI to do this or that, it gives me heebie-jeebies. I start talking to my self, now I will have to figure out what WMI class to use for this task, what properties and methods are exposed and how to write SQL like statement to accomplish what I am trying to do. Last week I was trying to create an automated tool to test load balancing on web servers. Part of the task is to switch to turn off network adapters at certain intervals and turn them on. All help on this task pointed to making use of WMI. There you go, something I really did not want to hear but I had to do.
During this process of creating my nifty tool for automated testing, I found out about WMI Code Creator. Even though it was publish 4 years ago, it is a very useful tool and must have if you are doing WMI programming. Not only it lists all the classes exposed for various tasks, it tells you the properties, methods etc. for each of those classes. And best part is that it generates some boiler plate code as well in C#, VB.Net and VB script. What more could one ask for. With click of few menu options, I was able to generate following code that lists all network adapters on server and spits out the properties of each device.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
namespace WebMonitor
{
class Program
{
static void Main(string[] args)
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_NetworkAdapter");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine
("----------------------------");
Console.WriteLine
("AdapterType: {0}", queryObj["AdapterType"]);
Console.WriteLine
("AdapterTypeId: {0}", queryObj["AdapterTypeId"]);
Console.WriteLine
("AutoSense: {0}", queryObj["AutoSense"]);
Console.WriteLine
("Availability: {0}", queryObj["Availability"]);
Console.WriteLine
("Caption: {0}", queryObj["Caption"]);
Console.WriteLine
("ConfigManagerErrorCode: {0}", queryObj["ConfigManagerErrorCode"]);
Console.WriteLine
("ConfigManagerUserConfig: {0}", queryObj["ConfigManagerUserConfig"]);
Console.WriteLine
("CreationClassName: {0}", queryObj["CreationClassName"]);
Console.WriteLine
("Description: {0}", queryObj["Description"]);
Console.WriteLine
("DeviceID: {0}", queryObj["DeviceID"]);
Console.WriteLine
("ErrorCleared: {0}", queryObj["ErrorCleared"]);
Console.WriteLine
("ErrorDescription: {0}", queryObj["ErrorDescription"]);
Console.WriteLine
("Index: {0}", queryObj["Index"]);
Console.WriteLine
("InstallDate: {0}", queryObj["InstallDate"]);
Console.WriteLine
("Installed: {0}", queryObj["Installed"]);
Console.WriteLine
("LastErrorCode: {0}", queryObj["LastErrorCode"]);
Console.WriteLine
("MACAddress: {0}", queryObj["MACAddress"]);
Console.WriteLine
("Manufacturer: {0}", queryObj["Manufacturer"]);
Console.WriteLine
("MaxNumberControlled: {0}", queryObj["MaxNumberControlled"]);
Console.WriteLine
("MaxSpeed: {0}", queryObj["MaxSpeed"]);
Console.WriteLine
("Name: {0}", queryObj["Name"]);
Console.WriteLine
("NetConnectionID: {0}", queryObj["NetConnectionID"]);
Console.WriteLine
("NetConnectionStatus: {0}", queryObj["NetConnectionStatus"]);
}
catch (ManagementException e)
{
Console.WriteLine("An error occurred while querying for WMI data: " + e.Message);
}
}
}
}
by Viper
16. April 2009 19:14
Read, download samples, tutorials etc. for WinForms.
by Viper
7. April 2009 12:33
Some time back I discussed How to submit requests to web sites programatically using HttpWebRequest. As I discussed in that article that back bone of the whole process is to know the structure of the page along with FORM parameters that need to be passed to target URL. Well that works for most of the application. You run into problem when you are dealing with ASP.Net because of its event model that gets used ASP.Net framework. If you follow the procedure discussed in last article, you will notice that most of the time you are not able to login into the site programatically. There is nothing wrong with the method that I discussed. There is little quirk for ASP.Net and that requires little understanding of how ASP.Net event mechanism works. So I will give brief description, you can read details in microsoft documentations .
If you look at source of an ASP.Net page, you will notice a hidden input variable __EVENTTARGET. When you click on some control that triggers postback, this variable is used to store ID/Name of that control. And this variable gets passed on to server when FORM is submitted. ASP.Net framework looks at this variable to decide what event handler needs to be triggered.
Given that information, if you do not pass correct value of the control that triggers log in action, sending HttpWebRequest with just login credentials is not going to work at all. Because your request will go to server, and it will never reach the event handlers that handles click on that button. So when you are dealing with ASP.Net sites, check ID/Name of the button or control that user clicks to start login process. You will need to pass that ID/Name as additional FORM key-value pair in POST or GET request. Following code snippet shows that this is about.
reqAttribs.RequestParameters.Add("txtEmail", "xxxxxxxxx");
reqAttribs.RequestParameters.Add("txtPassword", "yyyyyyy");
reqAttribs.RequestParameters.Add("__EVENTTARGET", "btnSubmit");
Notice third request parameter that I added which is ID of input button control. Hope this information helps in understanding programatic login process for ASP.Net sites.
by Viper
21. March 2009 18:18
Long time ago I wrote an article Detect file type or mime type based on content. If you look at the XML file that contained magic signature of different file types, one of the type was MP3 files. And magic signature for MP3 files is that first 3 bytes of file content are ID3. The format of MP3 files is very well defined and explained at ID3.org. Although it is very well defined but it is not something very straight forward and not a job for faint heart to understand it.
For one of new development adventure I am tasked with digging little bit deep into file structure of MP3 files and find out some meta data. Things like Artist Name, Title, Track Number, Year Of Release etc. So I looked around the site and found reference to IDSharp library developed for .Net and is COM visible as well. So you can use it in any application that can invoke COM interfaces. The library is available on sourceforge. But there is no source code for the actual core library. It is only available as .Net assembly. I really needed source code for it because I was curious about implementation and I had to make some modifications as well for the kind of work I was doing.
So I fired up good old tool Reflector and dis-assembled the assembly to generate the source code for it. I had to fix few compile errors after disassembly. But finally I made it to work as expected. So I thought I will share the source code of IdSharp library with people who are interested in it.
Download Source Code For IdSharp Library
From the following code snippet you can see how you can load a MP3 file to get all information about the file. And then you can actually change ID3 tag information as well and save the file with new information. In the sample code, I changed the name of the artist as well as album name. You can see from the screen shot that it did work.
static void Main(string[] args)
{
var id3v2 = ID3v2Helper.CreateID3v2("Hello.mp3");
Console.WriteLine("Artist: {0}", id3v2.Artist);
Console.WriteLine("Title: {0}", id3v2.Title);
Console.WriteLine("Album: {0}", id3v2.Album);
Console.WriteLine("Genre: {0}", id3v2.Genre);
Console.WriteLine("Year: {0}", id3v2.Year);
Console.WriteLine("TrackNumber: {0}", id3v2.TrackNumber);
Console.WriteLine("Media Type: {0}", id3v2.MediaType);
Console.WriteLine("CD Identifier: {0}", id3v2.MusicCDIdentifier.TOC);
id3v2.Artist = "Byteblocks.com";
id3v2.Title = "ID3v2 Song";
id3v2.Save("Bytes.mp3");
}
by Viper
21. March 2009 05:45
Recently I was working on detection of MP3 file format when a user uploads a file to a web site. Part of the detection was to look for ID3 header and figuring out what flags were set in header. The format specification tells you at what bit locations to check for what flags. This meant that you will need some mechanism to figure out what bits are set with in a byte. If you are seasoned C/C++ developer, you pretty much know that this meant that doing some low level bit shift operations on that byte to rotate through them to check which bit is set and which is not set. So if you will write that code in C#, it will look like snippet below.
static void ConvertToBinaryFormat(byte n)
{
var flags = new BitArray(8);
var counter = 8;
var idx = 0;
while(counter > 0)
{
flags.Set(idx++, ((n & 1) == 1));
n >>= 1;
counter--;
}
PrintBitArray(flags);
}
static void PrintBitArray(BitArray ba)
{
Console.WriteLine();
for(int i = ba.Length-1; i >= 0; i--)
{
Console.Write("{0}", ba[i] ? 1 : 0);
}
}
Looking at the code, you are already saying that I have already used BitArray class object in this function. Then why am I doing all the low level operations. I intentionally introduced BitArray here to demonstrate that you really do not need to do all the low level operations to check what bits are set. BitArray class already does that for you. Following one line of code does the same thing that I did by doing some bit shifting.
var newFlags = new BitArray(new byte[] {20});
PrintBitArray(newFlags);
If you look at PrintBitArray method, you will notice that it is using reverse loop to print each bit. When bit shit operation is being done, bit array gets filled from right to left. This means that higher order bits get pushed low. And BitArray class does the same thing. So you will have to access the array from bottom.
by Viper
10. March 2009 15:07
Some time when you use Add Service Reference to add reference to your WCF service, you may run into error like:
The type 'ForExService.Service1', provided as the Service attribute value in the ServiceHost directive could not be found
This error is very self explanatory telling that some type could not be found. Well if that type is missing in my service, how did the tool know about it. Well this exactly is the cause of this error. The tool looks at .svc file. And it found the following line in markup.
ServiceHost Language="C#" Debug="true" Service="ForExService.Service1" CodeBehind="CurrencyService.svc.cs
You probably can see the problem in line above. The service type is set to "ForExService.Service1" where the code behind was modified to name the service classes differently. So if you run into this kind of error, make sure that you check mark up of your service file as well to make sure that it matches the implementation in code.
by Viper
6. March 2009 06:05
Some time back I wrote an article on similar topic How to get IP address of a machine using C#. That article was written in days of .Net1.1. Since then .Net framework has come a long way. Some APIs were deprecated and a lot of new APIs were added. This post is an update on that old article. While I was working on a silverlight socket programming project, I had to deal with lot of Networking APIs. During that process I ended up writing a new method that returns me list of local IP addresses and presenting that to user to decide on what IP address they want to run socket server. Hope this post provides a quick coding tip on how you can get local IP address of your machine.
Private Function GetIPs() As StringCollection
Dim localIP = New StringCollection()
Dim localHostName = Dns.GetHostName()
Dim hostEntry = Dns.GetHostEntry(localHostName)
' Grab all ip addesses.
For Each ipAddr As IPAddress In hostEntry.AddressList
localIP.Add(ipAddr.ToString())
Next
GetIPs = localIP
End Function
Pardon my VB.Net code. I am not very intimate with this language. You can find C# code at old article location
by Viper
5. March 2009 19:28
While working on a Silverlight project, I had to write and read some data into Isolated storage. While creating a file in a sun folder i kept getting following error.
{System.IO.IsolatedStorage.IsolatedStorageException:
Operation not permitted on IsolatedStorageFileStream.
at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor
(String path, FileMode mode, FileAccess access, FileShare share,
Int32 bufferSize, IsolatedStorageFile isf)
at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor
(String path, FileMode mode, FileAccess access, IsolatedStorageFile isf)
at System.IO.IsolatedStorage.IsolatedStorageFile.OpenFile
(String path, FileMode mode, FileAccess access)
at SilverSockets.Page.CreateIsolatedStorageForUser()}
I am developing on Windows7 development machine. So for a moment I thought it may be that there is restriction on Windows7 and I have to make some changes in some silverlight settings or configuration. After spending a few minutes I realized that my creation of sub folder failed in previous step and i did not check it. And I went to on to creating the file in sub folder. Well, the message did not even come close to telling me that folder does not exist. After I fixed creation of sub folder everything worked smoothly. So if you do get this error, check if the folder or file path exists before you go down some wild chase on this error message.
Powered by BlogEngine.NET 1.4.6.1
Theme by Naveen Kohli
|
|