Friday, April 29, 2016

Asynchronous Streaming using Web Api for large amount of data

Need of return large amount of data or big chunk of data (from db or large file).

Two way to accomplished this:

  • 1.) use of streaming mechanism so that client fetch the data as needed.
  • 2.) using C# .net 5.0 async/await asynchronous execution model, to use TPL pool thread

Continuation:
We need of method return immediately to the caller stream and fetch data only when needed. this bring to us in "state machine" using "yield" keyword which runs on the server and knows what next to fetch in to output stream when client ask for more content, this process known as continuation.

public IEnumerable<DataImage>(string imageId)
{
 using (var dbReader = GetDataReader(imageId))
            {
                // Read rows asynchronously, put data into buffer and write asynchronously
                while (reader.Read())
                {
                    Thread.Sleep(1000); yield return ConvertToDataTransformObject(reader);
                }
            }
}

while the above code accomplished the state machine requirement but unfortunately, it did not achieved our goal ie: "Return immediately to the caller"

Client App to Test:
[TestMethod]
public void GetData()
{
            
 using (var client = new HttpClient())
  {
            var sw = Stopwatch.StartNew();
            var stream = client.GetStreamAsync("http://myserver:portNumber/api/ControllerName/id").Result;
            sw.Stop();
            Console.WriteLine("Elapsed time: {0}ms", sw.ElapsedMilliseconds);
 }
}
The Solution: PushStreamContent() ClassEnables scenarios where a data producer wants to write directly (either synchronously or asynchronously) using a stream

public HttpResponseMessage Get([FromUriint imageId)
        {
            HttpResponseMessage response = Request.CreateResponse();
 
            // Create push content with a delegate that will get called when it is time to write out 
            // the response.
            response.Content = new PushStreamContent(
                async (outputStream, httpContent, transportContext) =>
                {
                    try
                    {
                        // Execute the command and get a reader
                        using (var reader = GetDataReader(imageId))
                        {
 
                            // Read rows asynchronously, put data into buffer and write asynchronously
                            while (await reader.ReadAsync())
                            {
                                var rec = ConvertToDataTransformObject(reader);
 
                                var str = await JsonConvert.SerializeObjectAsync(rec);
 
                                var buffer = UTF8Encoding.UTF8.GetBytes(str);
 
                                // Write out data to output stream
                                await outputStream.WriteAsync(buffer, 0, buffer.Length);
                            }
                        }
                    }
                    catch(HttpException ex)
                    {
                        if (ex.ErrorCode == -2147023667) // The remote host closed the connection. 
                        {
                            return;
                        }
                    }
                    finally
                    {
                        // Close output stream as we are done
                        outputStream.Close();
                    }
                });
 
            return response;
        }

If we Test out client app, the control returns immediately and rest of the server code executed, only when client reads through obtained stream. end result will get low memory usage and scalability for big chunk of data.

Reference : Andru's blog and msdn
http://weblogs.asp.net/andresv/asynchronous-streaming-in-asp-net-webapi
https://msdn.microsoft.com/en-us/library/system.net.http.pushstreamcontent(v=vs.118).aspx



Monday, May 30, 2011

notify the derived class when an item added , replaced or Removed from the Collection

Create Custom Event Class: derived from EventArgs class

 public class CustomEvent : EventArgs
    {
        public CustomEvent(string message)
        {
            this.Message = message;
        }
        public string Message
        {
            get;
            set;
        }
    }

declare a delegate out side the Class:

public delegate void CustomEventHandler(object sender,CustomEvent args);

Create the Class Branch Contains Inner class BranchNameCollection holds the item Collection  

public class Branch
    {
        BranchNameCollection _branchNames;

        #region --Event Raised when item is Removed--

        //public event EventHandler itemRemoved;
        public event CustomEventHandler itemRemoved;
        public event CustomEventHandler itemAdded;
        public event CustomEventHandler itemReplaced;
        #endregion

        public Branch()
        {
            this._branchNames = new BranchNameCollection(this);
        }

        #region Property

        public Collection BranchNames
        {
            get { return _branchNames; }
        }

        #endregion

        //---called from within the BranchNamesCollection class when item Removed---
        protected virtual void RaiseItemRemovedEvent(CustomEvent e)
        {
            if (itemRemoved != null)
                itemRemoved(this, e);
        }

        //---called from within the Branchnamecollection class when item to be added----
        protected virtual void RaisedAddItemEvent(CustomEvent e)
        {
            if (itemAdded != null)
                itemAdded(this, e);
        }
        protected virtual void RaisedReplaceItemEvent(CustomEvent e)
        {
            if (itemReplaced != null)
                itemReplaced(this, e);
        }
        public string Message
        {
            get; set;
        }
        private class BranchNameCollection : Collection
        {
            Branch _b;
            public BranchNameCollection(Branch b)
            {
                this._b = b;
            }
            //---fired when an item is removed---
            protected override void RemoveItem(int index)
            {
                _b.RaiseItemRemovedEvent(new CustomEvent(_b.BranchNames[index].ToString()));
                base.RemoveItem(index);
            }
            //---fired when an item Added---
            protected override void InsertItem(int index, string item)
            {
                base.InsertItem(index, item);
                _b.RaisedAddItemEvent(new CustomEvent(_b.BranchNames[index].ToString()));
               
            }
            //---fired when an item Replaced---
            protected override void SetItem(int index, string item)
            {
                base.SetItem(index, item);
                _b.RaisedReplaceItemEvent(new CustomEvent(_b.BranchNames[index].ToString()));
            }
        }
    }



calling the Void  main()
{
         //creating the object
         Branch b = new Branch();
        //assign Events and handle the Events
            b.itemRemoved += new CustomEventHandler(b_itemRemoved);
            b.itemAdded+= new CustomEventHandler(b_itemAdded);
            b.itemReplaced+=new CustomEventHandler(b_itemReplaced);
            b.BranchNames.Add("Mumbai");
            b.BranchNames.Add("Kolkata");
            b.BranchNames.Add("Bangalore");
            b.BranchNames.Add("Delhi");
           
            //Remove the item from collection
            b.BranchNames.Remove("Kolkata");

}
//calling Appropriate function

        static void  b_itemRemoved (object sender, CustomEvent args)
        {
            Console.WriteLine("ItemRemoved "+ " : " + args.Message);
        }

        static void b_itemAdded(object sender, CustomEvent args)
        {
            Console.WriteLine("ItemAdded " + " : " + args.Message);
        }
        static void b_itemReplaced(object sender, CustomEvent args)
        {
            Console.WriteLine("ItemReplaced " + " : " + args.Message);
        }
//

Thursday, August 26, 2010

Phone Validation

//class represent the Rules Violation

    #region
  
    public class RuleViolation
    {
        public string ErrorMessage
        {
            get;
            private set;
        }
        public string PropertyName
        {
            get;
            private set;
        }

        public RuleViolation(string errorMessage)
        {
            ErrorMessage = errorMessage;
        }
        public RuleViolation(string errorMessage, string propertyName)
        {
            ErrorMessage = errorMessage;
            PropertyName = propertyName;
        }
    }

//-------------------------------------------------//
//class represent the phone validation

    #region
    public class PhoneValidator
    {
        static IDictionary countryRegx = new Dictionary()
        {
            {"IN",new Regex("^[0-9]+$")},
            {"USA",new Regex("^[2-9]\\d{2}-\\d{3}-\\d{4}$")},
            {"Netherlands",new Regex("(^\\+[0-9]{2}|^\\+[0-9]{2}\\(0\\)|^\\(\\+[0-9]{2}\\)\\(0\\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\\-\\s]{10}$)")}
        };
        public static bool IsValidNumber(string phoneNumber, string country)
        {
            if (country != null && countryRegx.ContainsKey(country))
                return countryRegx[country].IsMatch(phoneNumber);
            else
                return false;
        }
        public static IEnumerable Countries
        {
            get { return countryRegx.Keys; }
        }
    }

Thursday, June 24, 2010

Read/Write Web.config File

To modify the web.config [AppSettings] keys value at runtime
in grid like format using asp.net 2.0

1) Create a class in App_Code and copy & paste the below code

//Create an entity to store the config key and value

    public class AppSettingsKeys
    {
      
        int _configID;
       
        int _conID;
        string _conName;
        string _conValue;

        string _configName;
        string _configValue;

        public AppSettingsKeys()
        {
            this._configID = 0;
            this._configName = string.Empty;
            this._configValue = string.Empty;
           
            this._conID = 0;
            this._conName = string.Empty;
            this._conValue = string.Empty;
        }

        public int ConID
        {
            get { return _conID; }
            set { _conID = value; }
        }

        public string ConnectionName
        {
            get { return _conName; }
            set { _conName = value; }
        }

        public string ConnectionValue
        {
            get { return _conValue; }
            set { _conValue = value; }
        }

        public int ConfigID
        {
            get { return _configID; }
            set { _configID = value; }
        }
        public string ConfigName
        {
            get { return _configName; }
            set { _configName = value; }
        }
        public string ConfigValue
        {
            get { return _configValue; }
            set { _configValue = value; }
        }

        public void SetInfo(int id, string configName, string configValue)
        {
            this.ConfigID = id;
            this._configName = configName;
            this._configValue = configValue;
        }
    }
 
//2) Create a collection class like the below:

    public class AppSettingsKeysList : List
    { }

    public class AppSettingsOperations
    {
        //get all keys

        public AppSettingsKeysList getAllAppSettingsKeys()
        {
            AppSettingsKeys appSettingKey = null;
            AppSettingsKeysList appSettingKeyList = new AppSettingsKeysList();
            int idCount = 0;

            Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
            AppSettingsSection appSettingsSection = (AppSettingsSection) configuration.GetSection("appSettings");

            ConnectionStringsSection ConStringSection = (ConnectionStringsSection)configuration.GetSection("connectionStrings");
           
            if (appSettingsSection != null)
            {
                foreach (string key in appSettingsSection.Settings.AllKeys)
                {
                    idCount++;
                    appSettingKey = new AppSettingsKeys();
                    appSettingKey.ConfigID = idCount;
                    appSettingKey.ConfigName = key;
                    appSettingKey.ConfigValue = appSettingsSection.Settings[key].Value;

                    appSettingKeyList.Add(appSettingKey);
                }
            }
            return appSettingKeyList;
        }

        //modify the key List

        public bool ModifyKey(AppSettingsKeys appSettingKeys)
        {
            try
            {
                Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
                AppSettingsSection appSettingsSection =(AppSettingsSection) configuration.GetSection("appSettings");

                if (appSettingsSection != null)
                {
                    appSettingsSection.Settings[appSettingKeys.ConfigName].Value = appSettingKeys.ConfigValue;
                    configuration.Save();
                }
            }
            catch (Exception errorObject)
            {
                return false;
            }
            return true;
        }

    }


4) Create an aspx page and paste the below code:


 protected void Page_Load(object sender, EventArgs e)
    {

        lblMsg.Text = string.Empty;

       
       
        if (!IsPostBack)
        {
            //calling the method for papulating all app Settings keys
            try
            {
                GetAppSettingsKeys();
            }
            catch (Exception ex)
            {
                ExceptionMethod(ex);
            }
        }
    }
    private void ExceptionMethod(Exception errorObject)
    {
        lblMsg.Text = errorObject.Message.ToString();
        lblMsg.ForeColor = System.Drawing.Color.Red;
    }

    private void BindGridView(AppSettingsKeysList allKeyList)
    {
        try
        {
            GVAppConfig.DataSource = allKeyList;
            GVAppConfig.DataBind();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private void GetAppSettingsKeys()
    {
        AppSettingsOperations appSettingsOperations = new AppSettingsOperations();
        AppSettingsKeysList appSettingsKeyList = new AppSettingsKeysList();

        try
        {
            appSettingsKeyList = appSettingsOperations.getAllAppSettingsKeys();
            if (appSettingsKeyList.Count > 0)
            {
                //calling the bind gridView Method
                BindGridView(appSettingsKeyList);
            }
            else
            {
                lblMsg.Text = ">> No Keys Avaliable..!";
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    protected void GVAppConfig_PageIndexChanging(object sender, GridViewPageEventArgs e)
    {
        try
        {
            GVAppConfig.PageIndex = e.NewPageIndex;
            GetAppSettingsKeys();
        }
        catch (Exception ex)
        {
            ExceptionMethod(ex);
        }
    }
    protected void GVAppConfig_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
    {
        try
        {
            GVAppConfig.EditIndex = -1;
            GetAppSettingsKeys();
        }
        catch (Exception ex)
        {
            ExceptionMethod(ex);
        }
    }
    protected void GVAppConfig_RowEditing(object sender, GridViewEditEventArgs e)
    {
        try
        {
            GVAppConfig.EditIndex = e.NewEditIndex;
            GetAppSettingsKeys();
        }
        catch (Exception ex)
        {
            ExceptionMethod(ex);
        }
    }
    protected void GVAppConfig_RowUpdating(object sender, GridViewUpdateEventArgs e)
    {
        AppSettingsKeys appSettings = new AppSettingsKeys();
        AppSettingsOperations appSettingOperation = new AppSettingsOperations();

        try
        {
            Label lblKey = (Label) GVAppConfig.Rows[e.RowIndex].Cells[2].Controls[1];
            TextBox txtValue =(TextBox) GVAppConfig.Rows[e.RowIndex].FindControl("txtConfigValue");
           
            appSettings.ConfigID = Convert.ToInt32(GVAppConfig.DataKeys[e.RowIndex].Value);
            appSettings.ConfigValue = txtValue.Text;
            appSettings.ConfigName = lblKey.Text;

            //Update the key with the user entered value
            if (appSettingOperation.ModifyKey(appSettings))
            {
                lblMsg.ForeColor = System.Drawing.Color.Green;
                lblMsg.Text = ">> Key has been sucessfully updated...!";
            }
            else
            {
                lblMsg.ForeColor = System.Drawing.Color.Red;
                lblMsg.Text = ">> There is some problem in updating the key ,try later....!";
            }

            GVAppConfig.EditIndex = -1;
            GetAppSettingsKeys();
        }
        catch (Exception ex)
        {
            ExceptionMethod(ex);
        }
    }

Wednesday, June 23, 2010

Read XML With Name Table Optimization

 protected ArrayList XmlReaderWithNTOptimization()
    {
        int bookCount = 0;
        decimal bookTotal =0;
        string Title = "";
        ArrayList arrList = new ArrayList();

        XmlReaderSettings settings = new XmlReaderSettings();
        NameTable nt = new NameTable();
        Object book = nt.Add("book");
        object price = nt.Add("price");
        object title = nt.Add("first-name");
        settings.NameTable = nt;

        string bookSchemaFile = Path.Combine(Request.PhysicalApplicationPath, "books.xsd");

        settings.Schemas.Add(null,XmlReader.Create(bookSchemaFile));
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;

        settings.ValidationEventHandler += new ValidationEventHandler(MyFunction);

        settings.IgnoreComments = true;
        settings.IgnoreWhitespace = true;


        string bookFile = Path.Combine(Request.PhysicalApplicationPath, "books.xml");

        using (XmlReader reader = XmlReader.Create(bookFile, settings))
        {

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element && book.Equals(reader.LocalName))
                    bookCount++;
                if (reader.NodeType == XmlNodeType.Element && title.Equals(reader.LocalName))
                    arrList.Add(reader.ReadElementContentAsObject());
            }
        }

        Response.Write("found:    " + bookCount+"  Total Book Count: "+Title);
        return arrList;
    }

    protected void MyFunction(object sender, ValidationEventArgs e)
    {
        Response.Write(e.Message);
    }