Archive

Archive for the ‘C#’ Category

“Method Not Found” in ASP.NET Web API when using PUT and DELETE Verbs

Now that you have deployed your REST API and you are receiving “Method Not Found” exception / 404 exceptions when using PUT and DELETE verbs, while GET and POST is working absolutely fine. The fix is simple and needs small changes within IIS.

Open “Internet Information Services (IIS) Manager”, select the corresponding application and double-click on the “Handler Mappings” as shown below:

Image

Then select the “ExtensionlessUrlHandler-Integrated-4.0″ handler and double-click to edit this managed handler and click on “Request Restrictions…” button, as highlighted below:

Image

In the “Verbs” tab, select “One of the following verbs:” option and type-in the following verbs, “GET, HEAD, POST, DEBUG, PUT, DELETE”. Note: By default the “All verbs” option is selected by default.

Image

One final step is to ensure that your “web.config” contains “PUT” and “DELETE” in the verb attribute for “ExtensionlessUrl-Integrated-4.0” under the <handlers> section within <system.webServer>. Do a Find (Ctrl + F) if you have a really huge entries in “web.config” file.

<system.webServer>
  <handlers>
    <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

You are good to go! As a practice I always perform a “Restart”, under “Manage Web Site” within the “Internet Information Services (IIS) Manager” window.

Advertisements
Categories: ASP.NET, C# Tags: , , , , , , ,

Uploading a File in ASP.Net Web API

Consider the following model file and a sample POST method.

namespace FeedbackService.Models
{
    public class Feedback
    {
        public string Id { get; set; }
        public string EmailId { get; set; }
        public string Comment { get; set; }
        public string PageUrl { get; set; }
        public byte[] Attachment { get; set; }
    }
}

The corresponding “Post” method is as given below.

        public HttpResponseMessage Post([FromBody] Feedback value)
        {
            try
            {
                return ModelState.IsValid ? Request.CreateResponse(_wrapper.CreateFeedback(value) ? HttpStatusCode.Created : HttpStatusCode.InternalServerError, value) : Request.CreateResponse(HttpStatusCode.BadRequest, value);
            }
            catch (Exception ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

In the above scenario, the file to be uploaded is converted to byte array first and then this request was posted from an html page. The first issue we encountered was “Maximum content length exceeded” and to troubleshoot this issue, we have to add the following entries in “web.config”

<!-- To be added under <system.web> -->
<httpRuntime targetFramework="4.5" maxRequestLength="1048576" executionTimeout="3600" />

<!-- To be added under <system.webServer> -->
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>

The above said error went off, but there was new issue wherein the file upload was taking more time, That’s when we tried doing this the other way, we modified the “POST” method to include the following:

       public HttpResponseMessage Post()
        {
            // Check if the request contains multipart/form-data.
            if (!Request.Content.IsMimeMultipartContent())
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);

            try
            {
                var httpRequest = HttpContext.Current.Request;

                // Check if any file(s) have been uploaded
                if (httpRequest.Files.Count > 0)
                {
                    // Get file content as byte array
                    MemoryStream ms = new MemoryStream();
                    httpRequest.Files[0].InputStream.CopyTo(ms);
                    byte[] fileContent = ms.ToArray();

                    // Populate Feedback object
                    Feedback feedback = new Feedback();
                    feedback.PrototypeId = httpRequest.Form["prototypeId"];
                    feedback.PageUrl = httpRequest.Form["pageURL"];
                    feedback.EmailId = httpRequest.Form["emailId"];
                    feedback.Comment = httpRequest.Form["comment"];
                    feedback.Attachment = fileContent;

                    // Call the wrapper method
                    if (_wrapper.CreateFeedback(feedback))
                        return Request.CreateResponse(HttpStatusCode.Created);
                }
                else
                {
                    return Request.CreateResponse(HttpStatusCode.BadRequest);
                }

                // Return status indicating that the server refuses to fulfill request
                return Request.CreateResponse(HttpStatusCode.Forbidden);
            }
            catch (Exception ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

and to test this, we created the following sample html file

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Feedback Test Form</title>
    <style type="text/css">
            table.bottomBorder {
                border-collapse: collapse;
            }
            table.bottomBorder td, table.bottomBorder th {
                border-bottom: 1px dotted black;
                padding: 5px;
            }
    </style>
</head>
<body>
    <form enctype="multipart/form-data" method="post" action="http://localhost:62465/api/feedback" id="feedbackForm" novalidate="novalidate">
        <fieldset>
            <legend><b>Submit Feedback</b></legend>
            <table class="bottomBorder">
                <tr>
                    <td>Prototype ID:</td>
                    <td><input type="text" style="width: 320px; color: grey;" name="prototypeId" id="prototypeId" value="59938fe1-d80a-4534-8a7a-01977dab8370"></td>
                </tr>
                <tr>
                    <td>Page URL:</td>
                    <td><input type="text" style="width: 320px; color: grey;" name="pageURL" id="pageURL" value="http://localhost:62465/PostFeedback.html"></td>
                </tr>
                <tr>
                    <td>Email ID:</td>
                    <td><input type="text" style="width: 320px; color: grey;" name="emailId" id="emailId" value="test@test.com"></td>
                </tr>
                <tr>
                    <td>Comment:</td>
                    <td><textarea name="comment" style="width: 320px; color: grey;" cols="30" rows="4">This page is super awesome!</textarea></td>
                </tr>
                <tr>
                    <td>File Attachment:</td>
                    <td><input type="file" style="width: 320px; color: grey;" name="fileAttachment" id="fileAttachment"></td>
                </tr>
            </table>
            <p>
                <input type="submit" value="Submit Feedback" id="btnUpload">
            </p>
        </fieldset>
    </form>
</body>
</html>

The above is just a sample implementation of uploading a file in ASP.Net Web API as well as an example of sending HTML form data.

Categories: ASP.NET, C# Tags: , , , , , ,

Essential Regex

October 3, 2012 Leave a comment

By this time you all know how “regex” (Regular Expressions) have proved to be beneficial when it comes to either validations or comparisons; and yes that was actually an intent of this post to include some of the frequently used regex used by programmers.

American Express card #
3[47][0-9]{13}|3[47]\d{2}[ -]*\d{6}[ -]*\d{5}|[ -]*3[ -]*[47][ -]*(?:\d[ -]*){13}

Diners Club card #
3(?:0[0-5]|[68][0-9])\d[ -]*\d{6}[ -]*\d{4}|[ -]*3[ -]*(?:0[ -]*[0-5]|[68][ -]*[0-9])[ -]*(?:\d[ -]*){11}

Discover card #
6(?:011|5[0-9]{2})[0-9]{12}

Master Card card #
5[1-5][0-9]{14}|5[1-5]\d{2}[ -]*\d{4}[ -]*\d{4}[ -]*\d{4}|[ -]*5[ -]*[1-5][ -]*(?:[0-9][ -]*){14}

Visa card #
4[0-9]{12}(?:[0-9]{3})?|4\d{3}[ -]*\d{4}[ -]*\d{4}[ -]*\d(?:\d{3})?|[ -]*4[ -]*(?:\d[ -]*){12}(?:(?:\d[ -]*){3})?

UK National Insurance numbers
[abceghj-prstw-z][abceghj-nprstw-z] ?\d{2} ?\d{2} ?\d{2} ?[a-dfm]?

US social security numbers
(?!000)(?!666)(?:[0-6]\d{2}|7(?:[0-356]\d|7[012]))[- ](?!00)\d{2}[- ](?!0000)\d{4}

ASP.NET MVC2 Basics and Introduction

September 30, 2011 Leave a comment

A very nice video on ASP.NET MVC2 by “Scott Hanselman”, covers the introduction and basics and gives a very clear understanding about this pattern.

Categories: ASP.NET, C# Tags: , , ,

What is the difference between Uri and UriBuilder?

July 12, 2011 5 comments

The answer for this question would be similar to the question below:

What is the difference between String and StringBuilder?

Why? because they are similar in concept. A Uri/String is immutable (read-only, if you will). A UriBuilder/StringBuilder provides a mechanish to modify the contents of a Uri/String without having to destroy and recreate a Uri/String each time (which, if done often enough, could hurt performance).

String scheme = "http";
String target = "balaji.com";
int port = 8080;
String path = sample/page1.aspx";
String query = "?query=search text";
UriBuilder u = new UriBuilder(scheme, target, port, path, query);
Categories: C# Tags: , , , , ,

Playing MP3 from C#

March 1, 2011 9 comments

After handling a huge collections of MP3 files, one in my back-up drive and another in my hard-disk’s library, It meant huge gobbling up so much space, which of course you realize when your external hard-drive shows up “Drive Full” message. And an idea bloomed to create this mp3 player which plays files stored in my database!

I have named it “Byte Player” and according to the name the application would be playing the music when data is fed into as byte arrays. The database is designed using the same strategy that’s designed to store normal files.

Add the following DLL reference: “irrKlang.NET4” and put the following DLLs to your bin folder:
~ ikpFlac.dll
~ ikpMP3.dll
~ irrKlang.NET4.dll

Use the following reference:

using IrrKlang;

Generated Database Script to Create Table:

CREATE TABLE [dbo].[MusicLibrary](
	[FileID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
	[FileName] [nvarchar](50) NOT NULL,
	[FileContent] [varbinary](max) NOT NULL,
	[FileType] [nvarchar](50) NOT NULL,
	[CreateBy] [nvarchar](128) NULL,
	[CreatedOn] [datetime] NULL,
	[ModifiedBy] [nvarchar](128) NULL,
	[ModifiedOn] [datetime] NULL,
 CONSTRAINT [PK_MusicLibrary] PRIMARY KEY CLUSTERED 
(
	[FileID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[MusicLibrary] ADD  CONSTRAINT [DF_MusicLibrary_FileID]  DEFAULT (newid()) FOR [FileID]
GO

ALTER TABLE [dbo].[MusicLibrary] ADD  CONSTRAINT [DF_MusicLibrary_CreateBy]  DEFAULT (user_name(user_id(user_name()))) FOR [CreateBy]
GO

ALTER TABLE [dbo].[MusicLibrary] ADD  CONSTRAINT [DF_MusicLibrary_CreatedOn]  DEFAULT (getdate()) FOR [CreatedOn]
GO

ALTER TABLE [dbo].[MusicLibrary] ADD  CONSTRAINT [DF_MusicLibrary_ModifiedBy]  DEFAULT (user_name(user_id(user_name()))) FOR [ModifiedBy]
GO

ALTER TABLE [dbo].[MusicLibrary] ADD  CONSTRAINT [DF_MusicLibrary_ModifiedOn]  DEFAULT (getdate()) FOR [ModifiedOn]
GO

The C# application will hold the following methods to interact with the database.

const string connectionString = @"Server=KRISHNA\SQLEXPRESS;Database=music;Trusted_Connection=True;";

/// <summary>
/// Function to select files from the computer to be saved in the database.
/// </summary>
private void OpenMP3Files()
{
    OpenFileDialog dialog = new OpenFileDialog();
    dialog.Filter = "MP3 files|*.mp3";
    dialog.FilterIndex = 1;
    dialog.InitialDirectory = @"C:\\";
    dialog.RestoreDirectory = true;
    dialog.CheckFileExists = true;
    dialog.CheckPathExists = true;
    dialog.Multiselect = true;
    if (dialog.ShowDialog() == DialogResult.OK)
    {
        Cursor.Current = Cursors.WaitCursor;
        foreach (string filename in dialog.FileNames)
        {
            FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            using (BinaryReader reader = new BinaryReader(stream))
            {
                long length = new FileInfo(filename).Length;
                InsertMP3File(Path.GetFileName(filename), reader.ReadBytes((int)length));
            }
        }
        GetAllMP3();
    }
}

/// <summary>
/// Retrieves entire MP3 list from database (excludes the file content)
/// </summary>
private void GetAllMP3()
{
    string queryString = "SELECT [FileID], [FileName] FROM [MusicLibrary]";
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlDataAdapter adapter = new SqlDataAdapter();
        adapter.SelectCommand = new SqlCommand(queryString, connection);
        DataSet dataset = new DataSet();
        adapter.Fill(dataset);
        if (dataset.Tables.Count > 0)
        {
            gridMusic.DataSource = dataset.Tables[0];
            gridMusic.Columns[0].Visible = false;
            gridMusic.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
        }
    }
}

/// <summary>
/// Individual files are stored in the database.
/// </summary>
/// <param name="filename"></param>
/// <param name="data"></param>
private void InsertMP3File(string filename, byte[] data)
{
    string filetype = @"audio / mpeg";
    string queryString = "INSERT INTO [MusicLibrary] ([FileName] ,[FileContent] ,[FileType]) VALUES (@FileName, @FileContent, @FileType)";
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(queryString, connection);
        command.Parameters.Add(new SqlParameter("@FileName", (object)filename));
        command.Parameters.Add(new SqlParameter("@FileContent", (object)data));
        command.Parameters.Add(new SqlParameter("@FileType", (object)filetype));
        command.Connection.Open();
        command.ExecuteNonQuery();
        command.Connection.Close();
    }
}

Inorder to play the MP3 file I had some initial consideration and based on some strong reviews started of with the “NAudio” library [Ref: http://naudio.codeplex.com] but i faced some issues while trying to play the file from stream and upon searching through discussion forums I discovered that these issues are currently being worked upon and would have a fix in future releases; Therefore i was forced to consider my second choice “irrKlang” sound library [Ref: http://www.ambiera.com/irrklang/] and it worked out to be more simple and brilliant! The code illustrated below shows the fine integration between this library api and the database.

const string sound = "static.mp3";
ISoundEngine engine = new ISoundEngine();

/// <summary>
/// Retrieve individual file content from database
/// </summary>
/// <param name="fileID"></param>
private void GetMP3Data(string fileID)
{
    string queryString = "SELECT [FileContent] FROM [MusicLibrary] WHERE [FileID] = @FileID";
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new System.Data.SqlClient.SqlCommand(queryString, connection);
        command.Parameters.Add(new SqlParameter("@FileID", (object)fileID));
        command.Connection.Open();
        byte[] buffer = (byte[])command.ExecuteScalar();
        if (engine.IsCurrentlyPlaying(sound))
        {
            engine.RemoveAllSoundSources();
        }
        PlayMP3(buffer, sound);
        command.Connection.Close();
    }
}

/// <summary>
/// Play a single MP3 file
/// </summary>
/// <param name="data"></param>
/// <param name="filename"></param>
private void PlayMP3(byte[] data, string filename)
{
    ISoundSource source = engine.AddSoundSourceFromMemory(data, filename);
    engine.Play2D(filename);
}

I am so much interested in improving this and building a full-fledged player that would support right from ripping CD’s and expanding the database to include more information about the music albums and MP3 tags.

Categories: C#, Database Tags: , , , ,

DataSet.ReadXmlSchema Method Limitations

February 23, 2011 2 comments

We basically use the DataSet.ReadXmlSchema Method to create the schema which includes table, relation, and constraint definitions for the Dataset. Having said this here is something that’s worth sharing to all of my fellow developers who happen to stumble upon this post in search of a situation to find that their dataset is loading incorrect tables when your xml schema is being read!

Case 1: Sample1.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:simpleType name="PropertyNames">
    <xs:restriction base="xs:string">
      <xs:enumeration value="prop1"></xs:enumeration>
      <xs:enumeration value="prop2"></xs:enumeration>
    </xs:restriction>
  </xs:simpleType>
  <xs:element name="Items">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Item" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
              <xs:element name="properties" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

When you use the dataset’s “ReadXmlSchema” method you will find that the dataset will contain 2 tables!

// Create the DataSet to read the schema into.
DataSet ds = new DataSet();
// Invoke the ReadXmlSchema method with the file name.
ds.ReadXmlSchema(@"C:\\test\\Sample1.xsd");

A XML instance representation for this schema will be:

<Items>
  <Item> [1..*]
    <name> xs:string </name> [1]
    <properties> xs:string </properties> [0..*]
  </Item>
</Items>

Case 2: Sample2.xsd

<?xml version="1.0" encoding="iso-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:simpleType name="PropertyNames">
    <xs:restriction base="xs:string">
      <xs:enumeration value="prop1"></xs:enumeration>
      <xs:enumeration value="prop2"></xs:enumeration>
    </xs:restriction>
  </xs:simpleType>
  <xs:element name="Items">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Item" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
              <xs:element name="properties" type="PropertyNames" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

This time when you execute the following code you will find that the dataset will contain 1 table!

// Create the DataSet to read the schema into.
DataSet ds = new DataSet();
// Invoke the ReadXmlSchema method with the file name.
ds.ReadXmlSchema(@"C:\\test\\Sample1.xsd");

Whereas the XML instance representation for this schema will be:

<Items>
  <Item> [1..*]
    <name> xs:string </name> [1]
    <properties> PropertyNames </properties> [0..*]
  </Item>
</Items>

Actually, you should have noted that thou the XML instance representation for this schema (Case 2) is similar to the one in (Case 1), the dataset had only one table instead of two; After several hours of investigation and read through, I happen to discover (atleast lucky) thats there is a “Microsoft Support Article” which explains the “Limitations for DataSet Schema Files (XSD)”.

Please find the references to the file at the following location: http://support.microsoft.com/kb/319372

Question: How does this article applies to my scenario?
Answer: Use of Restriction Element Is Mostly Ignored
You can derive a new simple type by restricting an existing simple type with the restriction element. When you use the restriction element in simple types, the restriction element is ignored. Therefore, all the sub-elements of that restriction element are ignored also.

All restriction elements are ignored except the XSD simple type “string”, and its facets as follows:
> length
> minlength
> maxlength

%d bloggers like this: