Wednesday, October 1, 2014

Storing Complex/Serialized objects in Session

Storing objects in Session state-bag is commonplace and relatively easy.
What about storing an object that has a property which is a serialized string of another object ? Trying to use that straight out of the box is either tedious and repetitive, or useless.

Consider a case where you have a database user record which contains various user properties and a property Settings that stores serialized data.
It follows reason that to begin with we make a C# class to represent the thing we want to store as serialized string. Our class will just have one property - Bar

public class UserSettings : IChanged {
    [XmlIgnore, ScriptIgnore, JsonIgnore]
    public bool Dirty { get; set; }

    private string _Bar { get; set; }
    public string Bar {
        get {
            return this._Bar;
        }
        set {
            if (this._Bar != value) {
                this._Bar = value;
                this.Dirty = true;
            }
        }
    }
}

Note that I am mandating the IChanged interface that requires you to implement a Dirty bit.This bit management is manual for now, so you would have to code your own Dirty logic for whatever bits you have.
Next, we create a wrapper class that will actually be part of the session state.

public class UserHelper : DatabaseFieldHelper<UserSettings> {
        
    public override string KeyName {
        get { return "UserSessionKey"; }
    }
        
    public override string DefaultSessionValue {
        get {
            return SessionControl.User.Settings;
        }
    }

    public override void Save() {
        using (var db = new DbContext()) {
            var userService = new UserService(db);
            var user = userService.Get(SessionControl.User.UserId);
            user.Settings = JsonConvert.SerializeObject(base.Value);
            db.SaveChanges();
        }
    }
}

Here I inherit from the DatabaseFieldHelper with type of our UserSettings, the abstract database field helper manages storing, de-serializing, and calling the Save method. KeyName, DefaultSessionValue, and Save() are all required for you to implement. All that's left is adding a property in your session control class to get or set your new DatabaseFieldHelper static object, and use away! Something like, SessionControl.UserSettings.Bar for get or set, and you would have to manually call .Save() when you've changed the properties and would like to store the data back to the database, as string, of course.
    string bar = SessionControl.UserSettings.Bar;
    bar = "New Value";
    SessionControl.UserSettings.Save();

Under the hood


/// <summary>
/// Primary purpose of this class is to recover string value from entity's property already in session to help with 
/// deserializing it into T object, using this object, and saving to database when T's properties are changed.
/// </summary>
/// <typeparam name="T">Type of setting that is serialized</typeparam>
public abstract class DatabaseFieldHelper<T> where T : class, IChanged, new() {
    /// <summary>
    /// Gets a keyname, should be session-unique
    /// </summary>
    public abstract string KeyName { get; }

    /// <summary>
    /// Default value to use when the Helper class values are not yet in session
    /// </summary>
    public abstract string DefaultSessionValue { get; }

    /// <summary>
    /// Method for saving the setting to the database.
    /// This method should set appropriate entity's column with the value from base.Serialize() string.
    /// </summary>
    public abstract void Save();

    /// <summary>
    /// Gets the serialization settings.
    /// When saving to database we should ignore property values that equal default values of those properties' types to save space.
    /// </summary>
    private JsonSerializerSettings SerializerSettings {
        get {
            return new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore };
        }
    }

    /// <summary>
    /// Deseralizaed object.
    /// </summary>
    public T Value {
        get {
            // first look if our helper class is already in session
            T t = SessionControl.Session[KeyName] == null ? null : (T)SessionControl.Session[KeyName];
            if (t == null) {
                // when not in session look to the default value.
                string settings = this.DefaultSessionValue;
                if (!string.IsNullOrEmpty(settings)) {
                    // using the default value from somewhere else we deserialize object 
                    t = JsonConvert.DeserializeObject<T>(settings);
                } else {
                    // object is null, initialze with default T, set Dirty so we can save.
                    t = new T() {
                        Dirty = true
                    };
                }
                // save the deserealized object into the helper class's session key
                SessionControl.Session[KeyName] = t;
                // trigger the database save, should be saving new default instance of serealized object being handled
                this.Save();
            }
            return t;
        }

        private set {
            SessionControl.Session[KeyName] = value;
        }
    }

    /// <summary>
    /// Method for serializing current object with recommended settings.
    /// </summary>
    /// <returns>Serialized string safe to be stored in the database</returns>
    protected string Serialize() {
        return JsonConvert.SerializeObject(this.Value, this.SerializerSettings);
    }
}


Thursday, February 20, 2014

Binding, Sorting, and Filtering

Objective

Binding a list of to a Gridview or similar is something we all do frequently and with ease, however, as soon as you want to throw in filtering and ordering things get more complicated. In these last couple of days at work I believe I have created a solution that helps deal with all the nuisance that comes along with using filtered data. Essentially what you want is to easily create your object, then bind the list of them to a grid, and then you're done. 

The UI


Skipping the paging, this is a simple grid with sortable columns and (!) a "contains" filter on various fields. The previous implementation of the page used ASP.classic and was building the SQL query as a string, making filtering and ordering somewhat simple by just appending SQL statements based on the sort and the filter. Obviously this tactic cannot work with LINQ querries (well, I suppose it can...)

Creating the class 

Theoretically, your "business" project's method will return you either the entities as an IQuerable or you are creating your "DataRow" object on the page from what the business project gives you. I will describe the latter approach. 

private class GridOrdersDataRow {
    [CORECommon.General.Display(Name = "OrderID")]
    public long OrderId { get; set; }
    [CORECommon.General.Display(Name = "Account Number")]
    public string AccountNumber { get; set; }
    [CORECommon.General.Display(Name = "EventID")]
    public long EventId { get; set; }
    public string FirstName { get; set; }
    public string SchoolName { get; set; }
    public string LastName { get; set; }
    [CORECommon.General.Display(Name = "Customer", DatabaseFields = new string[] { "FirstName", "LastName" })]
    public string FullName {
        get {
            return this.FirstName + " " + this.LastName;
        }
    }
}

For the filtering, you would add a custom attribute with the name you want to appear in the drop down list , and you have an option to specify DatabaseFields as seen with the "FullName" property. The DatabaseFields defaults to the property name or can be supplied as an array, this gives you full control over how your data is queried. As the name states the property name or supplied name must be the actual name of your IQueryable (not necessarily the actual database fieldnames, will consider the attribute property). If the attribute is not present the property is not enabled for filtering.

Binding, sorting, and filtering 

Binding the property filter drop-down done simply with :

ddlSearchProperty.DataSource = CORECommon.General.GetDisplayAttributes<GridOrdersDataRow>();
ddlSearchProperty.DataBind();


Ordering and filtering your data, OrderByWithDirection takes a string and a SortDirection which I had a Tuple at the time.

list = list.WhereContains(txtSearchText.Text, CORECommon.General.GetDatabaseFieldNames<GridOrdersDataRow>(ddlSearchProperty.SelectedValue));
list = list.OrderByWithDirection(sort.Item1, sort.Item2);

Enjoy results.

So basically, you've made a class and added properties for filtering. Other things that still have to be done manually which I would like to work out is creating the Header text for gridview from the class and the sort expression - these are in the markup of my page (pretty straightforward).


Under the hood.

All of this kind of started when M showed me this article on how to sort by using a string. From there I decided that instead of keeping random strings in random places I would use an attribute on my class, and from there I decided that the filtering need to work in a similar fashion and I came up with this :

public static IQueryable<T> WhereContains<T>(this IQueryable<T> source, object value, params string[] searchProperties) {
    var type = typeof(T);
    var lambdaBuilder = PredicateBuilder.False<T>();
    foreach (var searchProperty in searchProperties) {
        var property = type.GetProperty(searchProperty);
        var parameter = Expression.Parameter(type, property.Name);
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var convertedProperty = Expression.Call(Expression.Convert(propertyAccess, typeof(object)), typeof(object).GetMethod("ToString"));
        var contains = Expression.Call(convertedProperty,
                                        typeof(string).GetMethod("Contains", new[] { typeof(string) }),
                                        Expression.Constant(Convert.ToString(value)));

        var lambda = (Expression<bool>)Expression.Lambda(contains, parameter);
        lambdaBuilder = lambdaBuilder.Or(lambda);
                
    }
            
    return source.AsExpandable().Where(lambdaBuilder);
}


Really cool stuff.
Of course you can expand on this by simply adding more attributes and filtering types, whatever you require. For example, you could add a Where() not the contains version, which I actually started off with.




Friday, April 26, 2013

FlexBox made awesome

  Today I had to work with a "flexbox" jQuery plugin(FlexBox) - a combination of a text box and a drop-down list.

  Quick background of the plugin:

  • simple data-cache with list of items that just have an "id" and a "value"
  • hybrid use of either supplied object or AJAX requests for data. AJAX data requests just pass "query" (the text box value), page number and page size.
  • does not store $.data() - so you can't grab an instance of the plugin


Shortly after adding it to the solution I found out that my particular use would require tweaking of the source.
Right there we can see that there are two instances of the plugin and "Frame" is dependent on "Roll", so outright we have several shortfalls of the flexbox:

  • Frame's flexbox must know Roll value
  • Frame's JavaScript cache must be Roll-dependent (in this case)
  • AJAX request for Roll/Frames list should also have other parameters, in my case it was an EventId.
  • Plugin works only with simple AJAX enabled "sources" that just return a string, and I would have like to use ASP.NET WebMethods and the ScriptManager generated methods that are already on page.
  • minor : no option to add a "placeholder" attribute to the input field
The one thing I did not want to do is inject any kind of static code or if statements that would make this plugin unusable outside of this page. Firstly, I created C# classes for working with flexbox - data and AJAX request objects.

[Serializable]
public class FlexBoxValue {
    public int id { get; set; }
    public string name { get; set; }
}
[Serializable]
public class FlexBoxReturnResult {
    public int total { get; set; }
    public FlexBoxValue[] results { get; set; }
}
[Serializable]
public class FlexBoxGetPostObject {
    public string query { get; set; }
    public int pageNumber { get; set; }
    public int pageSize { get; set; }
}
[Serializable]
public class FlexBoxGetRollDataPostObject : FlexBoxGetPostObject {
    public string roll { get; set; }
    public long eventId { get; set; }
}

The "FlexboxGetPostObject" is a clone of the existing simple functionality that just has the three listed parameters, which I expanded for my new WebMethod to have two extra parameters.
The Rolls flexbox was the easier out of the two because I could load the list of rolls on Page Load and just using what was already in the plugin bind the data.
$("#txtRoll").flexbox(QOE.EventInfo.Rolls, {
    "width": 90,
    "placeholder": "Roll",
    queryDelay: 200
});

QOE.EventInfo.Rolls is a serialized "FlexBoxReturnResult" C# object, same object I will use for fetching list of Frames per roll. So far, so good.

It must be mentioned that above code that instances flexbox has "static"(?) parameters, meaning once flexbox is initialized none of the options could have varying values - like Roll dependency for the Frame's flexbox. Also as you would imagine, the internal JS cache for Frames would not depend on anything but its own value, so once "0" search for Roll 001 is cached, you're out of luck for other roll values. So that's why we end up with :
$("#txtFrame").flexbox("custom", {
    method: "PageMethod",
    pageMethod: PageMethods.GetRollData,
    extraProperties: {
        roll: (function () { return $("#txtRoll_input").val(); }),
        eventId: QOE.EventInfo.EventID
    },
    cacheKeyPrefix: (function () { return $("#txtRoll_input").val(); }),
    width: 90,
    placeholder: "Frame",
    queryDelay: 200
});


There are several things going on here. method - previously only supported GET or POST. pageMethod is where I am just passing a function out of my ASP.NET generated JavaScript framework. If you recall the C# classes, there's a class for "basic" flexbox usage and one with "extra parameters" for my WebMethod to find frames. Here I'm making an object to send to ASP.NET, assuming (and you should) that you know the object you WebMethod is expecting. Also notice that "roll" and "cacheKeyPrefix" are actually functions -- this is how we get dynamic values into the flexbox (awesome).

"But how can you just pass functions and values as part of the object for a WebMethod consumption, that shouldn't work", is what you're probably thinking. Plugin code changes:
//o are the plugin's options
if (o.method.toUpperCase() == 'PAGEMETHOD') {
    var postObject = {
        query: q,
        pageNumber: p,
        pageSize: pageSize
    };

    if (o.extraProperties !== null) {
        postObject = $.extend(postObject, o.extraProperties);
        for (prop in postObject) {
            if (typeof (postObject[prop]) == "function") {
                postObject[prop] = postObject[prop]();
            }
        }
    }

    o.pageMethod(postObject,
        function (msg) {
            callback(msg);
        },
        function (msg) {
        });
}

The magic happens in the block where we look for extra properties. Firstly, using jQuery's $.extend, we merge our basic postObject with always-present parameters with WebMethod-specific parameters we defined back on the aspx page (no hardcoding of anything). Secondly, we go through each property and see if it's a "function" and if so we call it and grab a value assigning the value back into the same property. If you look above there are two extra parameters for a frame search : a static EventId that does not change, and a value of the roll flexbox that does change. The last thing is to just call the pageMethod and you're done. Not going to paste the cache-key update because it's very similar function-to-value conversion so that the Frame flexbox can cache Frame values per roll dependency.

So in summary, this modified plugin can work with ASP.NET WebServices, send custom objects, have dynamic parameters, and dynamic value dependent internal cache. Awesome.

Friday, January 27, 2012

ORC

How does one write an OCR ?

Sunday, December 13, 2009

Step 2


Step 2
Originally uploaded by dima.barashkov
Set up simple solving logic of setting Cell's values and eliminating row/column candidates when a value is set.

Onto group logic.
First step would be to make a simple algorithm for generating possible group solutions. Ex. a 2-count group of "5+" would be either 1+4, or 2+3, or a 3-count group of "7+" would be 1+2+4, or 1+3+3.

  • since the number of parts to split a sum(or other action) is variable - have a List of possibles initialized to 1
  • the order is irrelevant so far, so a 1,3,2 solution values is same as 3,2,1
  • for addition, while the sum of parts is less than needed value
  • increment last most value by one, and check if it fits
  • when value has reached to highest board allowed values' transitions should follow like so: On a board size 4 when going from (1,2,4) next should be (1,3,3)

Wednesday, December 9, 2009

Preliminary algorithm/brainstorming.
A main Board class consisting of
  • Array of Cells
  • List of CellGroups
Array of Cells
  • each item in this 2D array would represent each cell of the game
  • has a solution value (or blank if one is not found yet)
  • has a list of possible solution values
List of CellGroups
  • A cell group represents a collection of cells that amount to the group's value based on the action described. ex. 5+ would mean that this Cell-Group individual values should add up to 5
  • a list of Cell references. ex. a particular CellGroup is including Cells[1,1] and [1,2]
  • this class would most likely include most of the game-solving logic.
Preliminary solution logic. I think I will employ something that resembles a "queue" here (//toexplain). Rough logic steps for first few hundred puzzle boards (that are granted to be very simple) in priority order from highest to lowest...
  • Cell's possible-solution contains only one item or Cell text value contains a "=" then set the Cell's solution value
  • Cell's possible-solution contains only one item from the Cell-Groups possible solution values then set the Cell's solution value
Hah! pretty simple to start out with, I think.
Keeping in mind the most general rule of this number game - one unique number per row and column no matter the cell-group rules -- the "queue" I mentioned will work something like this
  • Anytime a Cell's solution value is set, queue up a possible solution value eliminating method from all cells in the same row and column
  • From the bullet above any time a Cell is down to one possible solution value queue up a Cell's solution value to be set... naturally resolving in a recursive loop.

Overlay


Overlay
Originally uploaded by dima.barashkov
In white are the drawn-recognized characters from within a cell.

Now I am ready to actually write the game-solving logic with the cells, underlying groups and math functions that each group has to satisfy.

CodeBlocks