Archive

Archive for the ‘C#’ Category

jQuery File Upload: IE9 and ASP.Net Web API File Uploading

June 2nd, 2016 Admin No comments

    The blueimp jQuery File Upload plugin uses the XMLHttpRequest to pass the file data to a server (only IE10+). If browser doesn’t support Ajax file uploading, the plugin makes a workaround by dynamically creating IFrame and sending the data on behalf of it through the traditional form POST. The JavaScript responsible for the workaround resides in jquery.iframe-transport.js, which accompanies the basic jquery.fileupload.js. The following TypeScript code could be used to initialize the plugin and submit file data (the code is intentionally kept as simple as possible – no progress bars, validations and so on):

//...
private fileData: any = {};
//...
$(".filePicker").fileupload({
	autoUpload: false, // will be submitted once button is clicked
	method: "PUT",
	dataType: "json",
	url: "api/someController/someMethod", // Web Api method to receive and process the file
	formData: () => { // additional parameters accompanying the file data
		return [{
			name: "bookName",
			value: $("#bookName").val()
		},
		{
			name: "bookGenre",
			value: $("#bookGenre").val()
		},
		{
			name: "bookAuthor",
			value: $("#bookAuthor").val()
		}];
	},
	add: (e: JQueryEventObject, data: any) => { // event handlers
		this.fileData = data;
		//...
	},
	done: (e: JQueryEventObject, data: any) => {
		//...
	},
	fail: (e: JQueryEventObject, data: any) => {
		//...
	},
	always: (e: JQueryEventObject, data: any) => {
		//...
	}
});
//...
$("#loadBook").on('click', function () { // the button to initiate the file sending
	if (this.fileData && this.fileData.hasOwnProperty("process")) {

		// file data validation: size, extension, whatever else...

		this.fileData.process().done(() => { // file sending
			this.fileData.submit();
		});
	}
});

On the server side the following code receives and processes the file data:

using System;
using System.Text;
using System·Web;
using System·Web.Http;
using System.Net;
using System.Net.Http;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Linq;
...
namespace DotNetFollower.Web.Controllers.Api
{
    [RoutePrefix("api/someController")]
	public class someController : ApiController
	{
        public someController()
		{
            //...
		}

        [Route("someMethod")]
        [HttpPut]
        [HttpPost] // this attribute allows processing traditional form POST
        public ServiceResult<BookOutput> someMethod()
        {
            try
            {
			    //...
			    var request = HttpContext.Current.Request;
			    var files   = request.Files;

			    if (files.Count == 0)
				    throw new Exception("Couldn't find a book to load!");

			    // read accompanying parameters
			    var bookName   = request.Form.Get("bookName");
			    var bookGenre  = request.Form.Get("bookGenre");
			    var bookAuthor = request.Form.Get("bookAuthor");

			    var file = new HttpPostedFileWrapper(files[0]);

			    // parsing file.InputStream ...

			    // processing the parsed file data ...

			    file.InputStream.Close();
			    //...

			    return new ServiceResult<BookOutput>()
				    {
					    Data = new BookOutput()
						    {
							    Name   = bookName,
							    Genre  = bookGenre,
							    Author = bookAuthor
						    }
				    };
            }
            catch(Exception ex)
            {
                return new ServiceResult<BookOutput>(ex);
            }
        }
	}
}

// Where ServiceResult and BookOutput are defined as follows

public class ServiceResult<T>
{
	public bool   Success      { get; set; }
	public string ErrorMessage { get; set; }
	public T      Data         { get; set; }

	public ServiceResult()
	{
		Success = true;
	}

	public ServiceResult(string errorMessage)
	{
		ErrorMessage = errorMessage;
	}

	public ServiceResult(Exception exception)
	{
		ErrorMessage = exception.Message;
	}
}

public class BookOutput
{
	public string Name   { get; set; }
	public string Genre  { get; set; }
	public string Author { get; set; }
}

Unfortunately, the code doesn’t works as expected in Internet Explorer 9 (thankfully, the lower versions are not supposed to be supported by the project, so I don’t care about them). If IE9 sends an Ajax request to the Web Api method, it interprets the JSON response correctly. However, when uploading a file, the jQuery File Upload plugin sends traditional non-Ajax form POST. So, having received the JSON result, IE9 prompts for a JSON file download.

Download Json File Prompt

To bypass such IE9 behaviour the server response should contain the content-type header “text/html” rather than the “application/json” returned by the Web Api method by default. To avoid writing some IE9 specific logic on both server and client sides, I’ve introduced the following Web Api method-adapter:

[Route("someMethodAdapted")]
[HttpPut]
[HttpPost] // this attribute allows processing traditional form POST
public HttpResponseMessage someMethodAdapted()
{
	var res = someMethod(); // call the original method

	const string JsonContentType = "application/json";
	const string HtmlContentType = "text/html";

	var response = Request.CreateResponse(HttpStatusCode.OK); // return 200 OK
	var context  = HttpContext.Current;
	response.Content = new StringContent(ToJson(res), // serialize result object into JSON
	  Encoding.UTF8,
	  // check if the JSON content-type is accepted
	  // (it's not accepted in case of form POST coming from IE9)
	  context.Request.AcceptTypes.Contains(JsonContentType, StringComparer.OrdinalIgnoreCase) ?
	     JsonContentType : HtmlContentType); // return suitable content-type

	return response;
}

// the ToJson method is defined as follows

private static string ToJson<T>(T obj) where T : class
{
	if (obj == null)
		return string.Empty;

	DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
	using (MemoryStream stream = new MemoryStream())
	{
		serializer.WriteObject(stream, obj);
		return Encoding.Default.GetString(stream.ToArray());
	}
}

The someMethodAdapted is supposed to be used instead of someMethod everywhere on the client side. So, repoint the url to the method-adapter

...
$(".filePicker").fileupload({
	...
	// Web Api method-adapter to receive and process the file
	url: "api/someController/someMethodAdapted",
	...
});
...

The someMethodAdapted makes a content-type trick and perfectly serves IE9 and higher. The use of HttpResponseMessage gives a control over the response headers. The HttpContext.Current.Request.AcceptTypes is a list of client-supported content types (aka MIME types). If the “application/json” is not in the list, the “text/html” is the right choice. Below are the AcceptTypes of Ajax and non-Ajax requests made by IE9:

// IE9 Ajax request to a Web Api method (true for higher browser versions too)
HttpContext.Current.Request.AcceptTypes	{string[3]}	string[]
[0]	"application/json"	string
[1]	"text/javascript"	string
[2]	"*/*; q=0.01"	string

// IE9 non-Ajax form POST
HttpContext.Current.Request.AcceptTypes	{string[3]}	string[]
[0]	"text/html"	string
[1]	"application/xhtml+xml"	string
[2]	"*/*"	string

ASP.NET MVC: Disable Controller

August 3rd, 2015 Admin No comments

    If you want to disable a MVC Controller, not deleting it, a good way to do that is apply a custom ActionFilter-derived attribute to it. Don’t confuse the ActionFilterAttribute defined in the System.Web.Mvc (the one we’re going to use) with the attribute of the same name residing within the Web API infrastructure, namely in the System.Web.Http.Filters namespace.

So, the custom attribute could be defined like

public class DisableControllerAttribute : ActionFilterAttribute
{
	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		//filterContext.Result = new HttpNotFoundResult();
		throw new HttpException((int)HttpStatusCode.NotFound, null);
	}
}

Applying it to the target MVC Controller is as simple as follows

...
using System.Web.Mvc;
...

[DisableController]
public class SomeLegacyController : Controller
{
}

Calling any action of such MVC contoller, user gets the 404 Http Status Code page. The page could look differently depending on which way you use to return the Status Code. Using the first line of code in the DisableControllerAttribute.OnActionExecuting (currently commented), the IIS “native” 404 page will be returned.

IIS Native 404 page not found

Throwing the HttpException like shown in the second line of the DisableControllerAttribute.OnActionExecuting (uncommented), you’ll get the ASP.NET handled page.

ASP.Net 404 page not found

Oracle: How to pass empty associative array to Stored Procedure

August 19th, 2014 Admin No comments

    One of the possible ways to pass a collection of values to a stored procedure is to use Associative Array (also known as Index-By Tables). For example, the declaration of the stored procedure accepting array of strings may resemble the following:

TYPE str_table_type IS TABLE OF VARCHAR2(255) INDEX BY PLS_INTEGER;

PROCEDURE Save_Something (
    p_str_array IN str_table_type,
    ...
    p_MSG_OUT OUT    VARCHAR2
);

To call such stored procedure we need to create and properly fill out the p_str_array parameter. The code doing that may look like shown below:

// create the parameter.
// In case of Associative Array the passed OracleDbType.Varchar2 is a type of the elements
OracleParameter array = new OracleParameter("p_str_array",
                                      OracleDbType.Varchar2, ParameterDirection.Input);

// Specify it as PL/SQL Associative Array
array.CollectionType  = OracleCollectionType.PLSQLAssociativeArray;

string[] values = new[] { "Value One", "Value Two", "Value Three" };

// Set the values for PL/SQL Associative Array
array.Value = values;

// Set the maximum number of elements in the PL/SQL Associative Array,
// in case of Input direction, Size usually equals to the number of passed values
array.Size = values.Length;

// Pass to the command and call one
using (var cmd = new OracleCommand("DNF.SOME_PKG.Save_Something")
                                   { CommandType = CommandType.StoredProcedure })
{
	cmd.Parameters.Add(array);
	cmd.Parameters.Add(new OracleParameter("p_MSG_OUT", OracleDbType.Varchar2,
                                           ParameterDirection.Output) { Size = 2000 });

	cmd.ExecuteNonQuery();

	// process p_MSG_OUT somehow
	...
}

The use of the Associative Array is pretty straightforward unless we are trying to pass an empty array. I tried a few ideas coming to mind first (listed below), none of them doesn’t work though:

array.Value = null;
array.Size  = 0;
...
array.Value = new string[0];
array.Size  = 0;
...
array.Value = new string[1] { null };
array.Size  = 1;

The “OracleParameter.Value is invalid” was the most popular exception I was getting at that moment. Ultimately, however, I found a working variant:

// for array of strings
array.Value = new OracleString[1] { OracleString.Null };
array.Size  = 1;
...
// for array of Int32s, decimals and so on
array.Value = new OracleDecimal[1] { OracleDecimal.Null };
array.Size  = 1;

As the result, the following common method and a few accompanying ones have been born to create Associative Arrays of different types:

// Creates an Associative Array parameter, knows how to treat empty collections
// Note: specify the maxNumberOfElementsInArray as an expected number of returned elements
public OracleParameter CreateAssociativeArray<ValueType, OracleType>(
                      string name, List<ValueType> values,
                      ParameterDirection direction, OracleDbType oracleDbType,
                      OracleType nullValue, int? maxNumberOfElementsInArray)
{
	bool isArrayEmpty     = values == null || values.Count == 0;
	OracleParameter array = new OracleParameter(name, oracleDbType, direction);
	array.CollectionType  = OracleCollectionType.PLSQLAssociativeArray;
	array.Value           = !isArrayEmpty ? values.ToArray() :
                                            (object)new OracleType[1] { nullValue };
	array.Size            = !isArrayEmpty ? values.Count     : 1;

	// if it's Output/InputOutput parameter, set the maximum possible number of elements.
	if (maxNumberOfElementsInArray != null &&
       (direction == ParameterDirection.Output || direction == ParameterDirection.InputOutput))
		array.Size = Math.Max(array.Size, maxNumberOfElementsInArray.Value);

	return array;
}

public OracleParameter CreateInt32AssociativeArray(string name,
          List<int> values, ParameterDirection direction = ParameterDirection.Input,
          int? maxNumberOfElementsInArray = null)
{
	return CreateAssociativeArray<int, OracleDecimal>(name, values,
             direction, OracleDbType.Int32, OracleDecimal.Null, maxNumberOfElementsInArray);
}

public OracleParameter CreateDecimalAssociativeArray(string name,
           List<decimal> values, ParameterDirection direction = ParameterDirection.Input,
           int? maxNumberOfElementsInArray = null)
{
	return CreateAssociativeArray<decimal, OracleDecimal>(name, values, direction,
             OracleDbType.Decimal, OracleDecimal.Null, maxNumberOfElementsInArray);
}

public OracleParameter CreateStringAssociativeArray(string name,
            List<string> values, ParameterDirection direction = ParameterDirection.Input,
            int? maxNumberOfElementsInArray = null, int maxLength = 255)
{
	var res = CreateAssociativeArray<string, OracleString>(name, values, direction,
               OracleDbType.Varchar2, OracleString.Null, maxNumberOfElementsInArray);

	if(direction == ParameterDirection.Output || direction == ParameterDirection.InputOutput)
	{
		int curMaxLen = maxLength;
		if(values != null)
			values.ForEach(s => { if (curMaxLen < s.Length) curMaxLen = s.Length; });

		res.ArrayBindSize = new int[res.Size];
		for (int i = 0; i < res.Size; i++)
			res.ArrayBindSize[i] = curMaxLen;
	}

	return res;
}

There are two important things to note here. The first one, in case of Output or InputOutput direction, the Size has to be set to the maximum number of elements you expect to get from the stored procedure (see the CreateAssociativeArray method). Specify this maximum number in the maxNumberOfElementsInArray. For example, you want to pass 3 elements to the stored procedure and get 10 back (InputOutput direction). Set the maxNumberOfElementsInArray to 10, otherwise CreateAssociativeArray will set Size to 3.

The second thing is the special processing of array of strings (see the CreateStringAssociativeArray method). String is variable-length element type (Varchar2 and so on). So, for strings we need to define the ArrayBindSize property. ArrayBindSize is the collection each element of which specifies the length of the corresponding element in the Value property. Being longer than specified, the element will be truncated. Pass the maximum allowed length of elements in maxLength, otherwise it will be set to 255 (default) or the maximum length found in the Value property.

Use the following code to create arrays of strings, Int32s and decimals in case of Input direction (or create your own “accompanying” methods for other types):

OracleParameter intArray = CreateInt32AssociativeArray("p_int_array",
               new List<int> { 1, 2, 3 });

// pass empty array to the stored procedure
OracleParameter decimalArray = CreateDecimalAssociativeArray("p_dec_array", null);

OracleParameter strArray = CreateStringAssociativeArray("p_str_array",
              new List<string> { "Value One", "Value Two", "Value Three" });

If Associative Array should be an Output or InputOutput parameter, the code may look like:

// Output parameter
// we expect no more than 10 elements to be returned
OracleParameter intArray = CreateInt32AssociativeArray("p_int_array", null,
     ParameterDirection.Output, 10);
...

// InputOutput parameter
// declare input values
string[] tmpAtrArray = new string[3] { "Value One", "Value Two", "Value Three" };
// we expect no more than 20 strings to be returned
// returned strings suppose to be no longer than 100
OracleParameter strArray = CreateStringAssociativeArray("p_str_array",
     new List<string>(tmpAtrArray), ParameterDirection.InputOutput, 20, 100);

To read, for example, number values (presented as OracleDecimal) from the output Associative Array I use the following two utility methods:

public Nullable<T> GetValue<T>(OracleDecimal oracleDecimal,
      Func<OracleDecimal, T> convert) where T : struct
{
	if (oracleDecimal == null || oracleDecimal.IsNull)
		return null;

	return convert(oracleDecimal);
}

public List<T> GetValues<T>(OracleParameter parameter,
     Func<OracleDecimal, T> convert) where T : struct
{
	List<T> res = new List<T>();

	if(parameter.Value != null)
	{
		OracleDecimal[] values = parameter.Value as OracleDecimal[];
		if(values != null)
			foreach(OracleDecimal oDecimal in values)
			{
				Nullable<T> val = GetValue(oDecimal, convert);
				if (val != null)
					res.Add(val.Value);
			}
	}

	return res;
}

So, the reading of integers looks as follows:

OracleParameter intArray = CreateInt32AssociativeArray("p_int_array", null,
            ParameterDirection.Output, 10);
...
// read returned values
List<int> res = GetValues<int>(intArray, od => { return od.ToInt32(); });

All code has been written and tested with the ODAC 12c Release 2.

C#: How to set or get value of a private or internal field through the Reflection

June 30th, 2013 Admin No comments

    The given post is an extension to the one How to set or get value of a private or internal property through the Reflection. So, here are two more methods to add to the ReflectionHelper. These methods are implemented as extensions to the object class and simplify getting and setting values of object’s private and internal fields.

public static class ReflectionHelper
{
	//...
	// here are methods described in the post
	// http://dotnetfollower.com/wordpress/2012/12/c-how-to-set-or-get-value-of-a-private-or-internal-property-through-the-reflection/
	//...

	private static FieldInfo GetFieldInfo(Type type, string fieldName)
	{
		FieldInfo fieldInfo;
		do
		{
			fieldInfo = type.GetField(fieldName,
				   BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			type = type.BaseType;
		}
		while (fieldInfo == null && type != null);
		return fieldInfo;
	}

	public static object GetFieldValue(this object obj, string fieldName)
	{
		if (obj == null)
			throw new ArgumentNullException("obj");
		Type objType = obj.GetType();
		FieldInfo fieldInfo = GetFieldInfo(objType, fieldName);
		if (fieldInfo == null)
			throw new ArgumentOutOfRangeException("fieldName",
			  string.Format("Couldn't find field {0} in type {1}", fieldName, objType.FullName));
		return fieldInfo.GetValue(obj);
	}

	public static void SetFieldValue(this object obj, string fieldName, object val)
	{
		if (obj == null)
			throw new ArgumentNullException("obj");
		Type objType = obj.GetType();
		FieldInfo fieldInfo = GetFieldInfo(objType, fieldName);
		if (fieldInfo == null)
			throw new ArgumentOutOfRangeException("fieldName",
			  string.Format("Couldn't find field {0} in type {1}", fieldName, objType.FullName));
		fieldInfo.SetValue(obj, val);
	}
}

The use of methods is shown below:

// get value
string privateValue = (string)someObj.GetFieldValue("_connectionString");
// set value
someObj.SetFieldValue("_connectionString", "some connection string");
Related posts:
Categories: C#, Reflection Tags: ,

C#: How to set or get value of a private or internal property through the Reflection

December 17th, 2012 Admin No comments

    Quite often in my practice I need to interact with hidden (internal and private) properties of an object. It easily can be done through the Reflection API. The only complication may arise here it’s when a private property is defined in one of the base classes. In this case we have to iterate through the object’s class hierarchy, looking for the property. So, trying to simplify getting and setting values of object’s private and internal properties, I’ve implemented a couple of the methods-extensions listed below. The GetPropertyValue method returns value of a private or internal property, and the SetPropertyValue, in turn, sets value to a private or internal property.

public static class ReflectionHelper
{
 private static PropertyInfo GetPropertyInfo(Type type, string propertyName)
 {
   PropertyInfo propInfo = null;
   do
   {
     propInfo = type.GetProperty(propertyName,
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
     type = type.BaseType;
   }
   while (propInfo == null && type != null);
   return propInfo;
 }

 public static object GetPropertyValue(this object obj, string propertyName)
 {
   if (obj == null)
     throw new ArgumentNullException("obj");
   Type objType = obj.GetType();
   PropertyInfo propInfo = GetPropertyInfo(objType, propertyName);
   if (propInfo == null)
     throw new ArgumentOutOfRangeException("propertyName",
       string.Format("Couldn't find property {0} in type {1}", propertyName, objType.FullName));
   return propInfo.GetValue(obj, null);
 }

 public static void SetPropertyValue(this object obj, string propertyName, object val)
 {
    if (obj == null)
      throw new ArgumentNullException("obj");
    Type objType = obj.GetType();
    PropertyInfo propInfo = GetPropertyInfo(objType, propertyName);
    if (propInfo == null)
      throw new ArgumentOutOfRangeException("propertyName",
        string.Format("Couldn't find property {0} in type {1}", propertyName, objType.FullName));
    propInfo.SetValue(obj, val, null);
 }
}

Below is how to use the methods. Let’s assume we have the following hierarchy of classes:

class SomeBase
{
    private bool IsLimited { get; set; }

    public SomeBase()
    {
        IsLimited = false;
    }
}

class SomeClass : SomeBase
{
    private  string Str { get; set; }
    internal int    Int { get; set; }

    public SomeClass()
    {
        Str = "initial value";
        Int = 0;
    }
}

So, we need to get and set hidden properties’ values from within a project (library) different to the one where the SomeBase and SomeClass are located. A possible code may look like the following:

SomeClass someObj = new SomeClass();

// the Str and Int properties will be found on the first step of iteration,
// so, the base class won't be analyzed
string currentStrValue = (string)someObj.GetPropertyValue("Str");
int    currentIntValue = (int)someObj.GetPropertyValue("Int");

// the IsLimited propertiy will be found on the second step of iteration,
// so, the base class will be analyzed as well
bool currentBoolValue = (bool)someObj.GetPropertyValue("IsLimited");

// the Str and Int properties will be found on the first step of iteration,
// so, the base class won't be analyzed
someObj.SetPropertyValue("Str", "brand new value");
someObj.SetPropertyValue("Int", -1);

// the IsLimited propertiy will be found on the second step of iteration,
// so, the base class will be analyzed as well
someObj.SetPropertyValue("IsLimited", true);
Related posts:
Categories: C#, Reflection Tags: ,