Category Archives: Web

Elixir Phoenix Cache

An implementation with ets.

Let’s start with implementation

defmodule SimpleCache do
  @table :simple_cache

  def init(_) do
    :ets.new(@table, [
      :set,
      :named_table,
      :public,
      read_concurrency: true,
      write_concurrency: true
    ])

    {:ok, %{}}
  end

  def start_link do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def fetch(key, expires_in_seconds, fun) do
    case lookup(key) do
      {:hit, value} ->
        value

      :miss ->
        value = fun.()
        put(key, expires_in_seconds, value)
        value
    end
  end

  defp lookup(key) do
    case :ets.lookup(@table, key) do
      [{^key, expires_at, value}] ->
        case now < expires_at do
          true -> {:hit, value}
          false -> :miss
        end

      _ ->
        :miss
    end
  end

  defp put(key, expires_in_seconds, value) do
    expires_at = now + expires_in_seconds
    :ets.insert(@table, {key, expires_at, value})
  end

  defp now do
    :erlang.system_time(:seconds)
  end
end


Update application.ex

 def start(_type, _args) do
    import Supervisor.Spec

    children = [
      supervisor(SimpleCache, [])
    ]
    opts = [strategy: :one_for_one, name: Supervisor]
    Supervisor.start_link(children, opts)
  end

Finally, use it

    cache_for_seconds = 60
    key = 'key'

    SimpleCache.fetch(key, cache_for_seconds, fn ->
      {:ok, some_expensive_operation}
    end)

Relavent links:
https://stackoverflow.com/questions/35218738/caching-expensive-computation-in-elixir
https://dockyard.com/blog/2017/05/19/optimizing-elixir-and-phoenix-with-ets

RSpec, Action Cable, and Capybara (As of Rails 5.1.2)

Gems in Gemfile:

group :test, :development do
  gem 'database_cleaner'
  gem "rspec-rails", "~> 3.6.0"
  gem 'selenium-webdriver'
end

group :test do
  gem "capybara", "~> 2.14.0"
end

rails_helper:

config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

  #Puma makes it possible to run RSpec with ActionCable
  Capybara.server = :puma

  Capybara.register_driver :selenium_chrome do |app|
    Capybara::Selenium::Driver.new(app, browser: :chrome)
  end
  Capybara.javascript_driver = :selenium_chrome

And, the driver:

brew install chromedriver

From .Net Developer to Elm. Part 2 – Making a Simple Project.

In this article I’ll write a simple Bayesian Calculator using Elm.
Link to final project – Bayesian CalculatorSource Code

Create a directory for your project.
cd into it.
Run “elm-make” to initialize a new elm project.
Install some packages for working with web:

elm-package install “evancz/elm-html”
elm-package install “evancz/start-app”

start-app takes care of some application wiring,”setting everything up so you can focus entirely on writing your app

If you open elm-package.json, you will see that the packages, which we just installed, were added to “dependencies” node.

I’ll use npm and gulp to manage my build. Also, I’m using bootstrap (cause css is hard)
npm init
npm install bootstrap –save-dev
npm install gulp –save-dev
npm install gulp-elm –save-dev
npm install gulp-rename –save-dev

The last piece of setting up is gulp. In the script, I just combine all css and js into bundles and copy them to dest folder.

We’re ready to start writing our app.

Create Calculator.elm. This is where our code will go.

Create Calculator.html. This will encapsulate resulting JavaScript file from Elm. Since I’m writing a full-screen application, all we have to do is add this to the script block:

var app = Elm.fullscreen(Elm.Calculator);

Now, to the application code.

Our model is quite simple – consists of four string fields related to four input fields on the form.
We have three inputs on the page – all encapsulated inside entryForm:

entryForm : Address Action -> Model -> Html
entryForm address model =
  div
    [ class "form-horizontal" ]
    [ formGroupItem (priorProbabilityItem address model)
    , formGroupItem (hitRateItem address model)
    , formGroupItem (falseAlarmItem address model)
    , formGroupItem (resultItem address model)
    ]

formGroupItem is simply a method to produce another div with a class of “form-group”:

formGroupItem : List Html -> Html
formGroupItem body =
  div
    [ class "form-group" ]
    body

body in here is just a list of Html elements that we are passing to our div.

Let’s look at one of the inputs:

priorProbabilityItem : Address Action -> Model -> List Html
priorProbabilityItem address model =
  [ label
      [ for "priorProbability", class "col-md-3 control-label" ]
      [ text "Prior Probability" ]
  , div
      [ class "col-md-9" ]
      [ input
          [ type' "text"
          , placeholder "0.00"
          , value model.priorProbability
          , id "priorProbability"
          , autofocus True
          , Utils.onInput address UpdateInitialProbability
          ]
          []
      ]
  ]

We have a label and a div with an input which maps to priorProbability field in our model.
Every time a user enters something we react to it by addressing UpdateInitialProbability action:

update : Action -> Model -> Model
update action model =
  case action of
...
    UpdateInitialProbability probability ->
      { model | priorProbability = probability }
...

In the code above we are updating our model with the new value that a user entered for priorProbability.
We have the same logic for all of the other input fields.

Every time a model changes, we try to show the Bayes calculation result:

resultItem : Address Action -> Model -> List Html
resultItem address model =
  [ label
      [ for "bayesResult", class "col-md-3 control-label" ]
      [ text "New Probability" ]
  , div
      [ class "col-md-9" ]
      [ span [] [ text (bayesResult model) ]
      ]
  ]

bayesResult is responsible for generating new probability. If some input is invalid, we just don’t display anything. Sure, validation could be a little more sophisticated, but we’re just trying it out.

While in development, make sure to run elm-reactor and gulp in the command line – open two tabs or windows (depending on your console app) for each one and just run “elm-reactor” in one, and “gulp” in another.

In order to see your app in a browser, go to http://localhost:8000/dest/Calculator.html
Every time you save your elm file, it should update the js files in the dest folder. You still have to refresh the browser to see the changes. I haven’t quite figured the auto-refresh part with gulp and elm.

If you want to see the build errors, they should show up in the console, which runs gulp command. Alternatively, if you use Sublime, press Ctrl + B to build it and all errors should show up directly in Sublime.

Custom MVC Model Binder

When you expect data in non-standard way and you want it to magically bind to your model, custom model binders could be a way to go.

Let’s say we want to post xml data to our controller method and we have a model for it.

public class XmlModel
        {
            public int Number { get; set; }
        }

Which we want to accept in our controller method:

public ActionResult Xml(XmlModel xmlModel)
        {
            return Content(xmlModel.Number.ToString());
        }

Now, let’s add our xml binder:

public class XmlModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var modelType = bindingContext.ModelType;
            return new XmlSerializer(modelType).Deserialize(controllerContext.HttpContext.Request.InputStream);
        }
    }

And XMLModelBinderProvider:

public class XMLModelBinderProvider : IModelBinderProvider
    {      
        public IModelBinder GetBinder(Type modelType)
        {
            var contentType = HttpContext.Current.Request.ContentType;
            if (string.Compare(contentType, @"text/xml", StringComparison.OrdinalIgnoreCase) != 0)
            {
                return null;
            }

            return new XmlModelBinder();
        }
    }

Add the provider to our Application_Start method in the Global.asax:

ModelBinderProviders.BinderProviders.Insert(0, new XMLModelBinderProvider()); 

To test this we can use Composer from Fiddler:
http://localhost/home/xml
User-Agent: Fiddler
Content-Type: text/xml

Request Body:

<XmlModel>
<Number>42</Number>
</XmlModel>

If we add breakpoint in our controller, we should see 42 coming through in our model.

Chrome Developer Tools Productivity Tips

Most Useful Shortcuts
Ctrl Shift I – Open developer tools.
Ctrl Shift P – Search within file. Displays all functions within a file.
Ctrl P – show js files. Type to search.
Ctrl Shift C – inspect element
Esc – toggle console
Ctrl F – find inside a file
Ctrl Shift F – find across all sources

To enable text editing directly in a browser:
document.body.contentEditable = true;

To time something: console.time(“my action”); … console.timeEnd(“my action”)

Snippets – run custom JavaScript code and run it anwhere you want. https://bgrins.github.io/devtools-snippets/

To disable cache – Network tab – disable cache (while DevTools is open).

Add timestamp to events displayed in console – Settings – General – Console – Show timestamps.

Enabling awesome dark theme:
Go to chrome://flags – Enable Developer Tools Experiments.
Open Chrome Dev Tools. – Settings – Experiments – allow custom UIthemes
Install a DevTools Theme. Here’s one.

A cool video about the above and much more – Chrome Developer Tools Deep Dive by Shay Friedman

Passing custom objects to FluentValidation

This is a guide for passing custom objects to Fluent Validators. This can be helpful for more complex validation scenarios.

Here’s an example of what we want to achieve:

public class OurModelValidator: AbstractValidator<OurMVCViewModel>
{
public OurModelValidator(OurClassWeWantToPassToValidator ourClassWeWantToPassToValidator)
{
if (ourClassWeWantToPassToValidator.SomeCondition)
{
RuleFor(m => m.PropertyA).NotEmpty();
}
else
{
RuleFor(m => m.PropertyB).NotEmpty();
}
}
}

In order to achieve this, we need to make some changes to the FluentValidationModelValidatorProvider class by overriding its CreateValidator method:

public class OurCustomFluentModelValidatorProvider : FluentValidationModelValidatorProvider
{

protected override IValidator CreateValidator(ModelMetadata metadata, ControllerContext context)
{
var type = this.IsValidatingProperty(metadata) ? metadata.ContainerType : metadata.ModelType;
return GetOurModelValidator(type) ?? this.ValidatorFactory.GetValidator(type);
}

private IValidator GetOurModelValidator(Type modelType)
{
if (modelType == typeof(OurClassWeWantToPassToValidator))
{
var ourClassWeWantToPassToValidator = new OurClassWeWantToPassToValidator();
return new OurModelValidator(ourClassWeWantToPassToValidator);
}

return null;
}
}

Since we want FluentValidation to handle all situation when OurModelValidator is not applicable, we use built-in ValidatorFactory to return default Validator when validating anything but OurMVCViewModel.

And the last step is to register our new provider:

ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new DataAnnotationsModelValidatorProvider());
ModelValidatorProviders.Providers.Add(new DataErrorInfoModelValidatorProvider());
ModelValidatorProviders.Providers.Add(new ClientDataTypeModelValidatorProvider());
ModelValidatorProviders.Providers.Add(new OurCustomFluentModelValidatorProvider());

FluentValidation Client-Side Custom Validation with MVC

FluentValidation is “A small validation library for .NET that uses a fluent interface and lambda expressions for building validation rules for your business objects.” It is quite awesome. However, the provided client-side validation is limited:  “any rules defined using a condition (with When/Unless), custom validators, or calls to Must will not run on the client side.” Below is some my first take on using FluentValidation on both server and client-side.

First, you need to install the nuget package. In our case, it is FluentValidation.MVC4.

We needed to make a certain property required, but only when some other property is true. To achieve this on client-side (server-side is trivial), we added these:

	public class RequiredIfClientSideValidator : PropertyValidator
	{
		public string DependentProperty { get; set; }
		public object TargetValue { get; set; }

		public RequiredIfClientSideValidator(string errorMessage, string dependentProperty, object targetValue)
			: base(errorMessage)
		{
			this.DependentProperty = dependentProperty;
			this.TargetValue = targetValue;
		}

		protected override bool IsValid(PropertyValidatorContext context)
		{
			//This is not a server side validation rule. So, should not effect at the server side.  
			return true;
		}
	}

And this

	public class RequiredIfClientSideFluentPropertyValidator : FluentValidationPropertyValidator
	{
		private RequiredIfClientSideValidator RequiredIfClientSideValidator
		{
			get { return (RequiredIfClientSideValidator)Validator; }
		}

		public RequiredIfClientSideFluentPropertyValidator(ModelMetadata metadata,
													   ControllerContext controllerContext,
													   PropertyRule propertyDescription,
													   IPropertyValidator validator)
			: base(metadata, controllerContext, propertyDescription, validator)
		{
			ShouldValidate = false;
		}

		public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
		{
			if (!ShouldGenerateClientSideRules()) yield break;

			var formatter = new MessageFormatter().AppendPropertyName(Rule.GetDisplayName());
			string message = formatter.BuildMessage(RequiredIfClientSideValidator.ErrorMessageSource.GetString());

			var rule = new ModelClientValidationRule()
			{
				ValidationType = "requiredif",
				ErrorMessage = message
			};

			string depProp = BuildDependentPropertyId(Metadata, ControllerContext as ViewContext);
			// find the value on the control we depend on;
			// if it's a bool, format it javascript style 
			// (the default is True or False!)
			string targetValue = (RequiredIfClientSideValidator.TargetValue ?? "").ToString();
			if (RequiredIfClientSideValidator.TargetValue.GetType() == typeof(bool))
				targetValue = targetValue.ToLower();

			rule.ValidationParameters.Add("dependentproperty", depProp);
			rule.ValidationParameters.Add("targetvalue", targetValue);

			yield return rule;
		}

		private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
		{
			// build the ID of the property
			string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(RequiredIfClientSideValidator.DependentProperty);
			// unfortunately this will have the name of the current field appended to the beginning,
			// because the TemplateInfo's context has had this fieldname appended to it. Instead, we
			// want to get the context as though it was one level higher (i.e. outside the current property,
			// which is the containing object (our Person), and hence the same level as the dependent property.
			var thisField = metadata.PropertyName + "_";
			if (depProp.StartsWith(thisField))
				// strip it off again
				depProp = depProp.Substring(thisField.Length);
			return depProp;
		}
	}

Additionally, we introduced a validator for simple client-side validation (ClientSideValidator) where you just need to pass an error message to your JavaScript validation.

public class ClientSideValidator : PropertyValidator
	{
		public string JavascriptValidationAdapterName { get; set; }

		public ClientSideValidator(string errorMessage, string javascriptValidationFunctionName)
			: base(errorMessage)
		{
			JavascriptValidationAdapterName = javascriptValidationFunctionName;
		}

		protected override bool IsValid(PropertyValidatorContext context)
		{
			//This is not a server side validation rule. So, should not effect at the server side.  
			return true;
		}
	}

And an accompanying class:

	
	public class ClientSideFluentValidator : FluentValidationPropertyValidator
	{
		private ClientSideValidator ClientSideValidator
		{
			get { return (ClientSideValidator)Validator; }
		}

		public ClientSideFluentValidator(ModelMetadata metadata,
			ControllerContext controllerContext,
			PropertyRule propertyDescription,
			IPropertyValidator validator)
			: base(metadata, controllerContext, propertyDescription, validator)
		{
			ShouldValidate = false;
		}

		public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
		{
			if (!ShouldGenerateClientSideRules()) yield break;

			var formatter = new MessageFormatter().AppendPropertyName(Rule.GetDisplayName());
			string message = formatter.BuildMessage(ClientSideValidator.ErrorMessageSource.GetString());

			var rule = new ModelClientValidationRule()
			{
				ValidationType = ClientSideValidator.JavascriptValidationAdapterName,
				ErrorMessage = message
			};
			
			yield return rule;
		}
	}

Register your custom validators in Global.asax.cs:

FluentValidationModelValidationFactory requiredIfClientSideValidationFactory =
				(metadata, context, rule, validator) =>
					new RequiredIfClientSideFluentPropertyValidator(metadata, context, rule, validator);
			
			FluentValidationModelValidationFactory clientSideValidationFactory =
				(metadata, context, rule, validator) =>
					new ClientSideFluentValidator(metadata, context, rule, validator);
			
			FluentValidationModelValidatorProvider.Configure(provider =>
			{
				provider.Add(typeof(RequiredIfClientSideValidator), requiredIfClientSideValidationFactory);
				provider.Add(typeof(ClientSideValidator), clientSideValidationFactory);
			});

Don’t forget to add the JavaScript part:
For requiredif validation:

$.validator.addMethod('requiredif',
    function (value, element, parameters) {
    	var id = '#' + parameters['dependentproperty'];

    	// get the target value (as a string, 
    	// as that's what actual value will be)
    	var targetvalue = parameters['targetvalue'];
    	targetvalue =
          (targetvalue == null ? '' : targetvalue).toString();

    	// get the actual value of the target control
    	// note - this probably needs to cater for more 
    	// control types, e.g. radios
    	var control = $(id);
    	var controltype = control.attr('type');
    	var actualvalue =
            controltype === 'checkbox' ?
            control.attr('checked').toString() :
            control.val();

    	// if the condition is true, reuse the existing 
    	// required field validator functionality
    	if (targetvalue.toLowerCase() === actualvalue.toLowerCase())
    		return $.validator.methods.required.call(
              this, value, element, parameters);

    	return true;
    }
);

$.validator.unobtrusive.adapters.add(
    'requiredif',
    ['dependentproperty', 'targetvalue'],
    function (options) {
    	options.rules['requiredif'] = {
    		dependentproperty: options.params['dependentproperty'],
    		targetvalue: options.params['targetvalue']
    	};
    	options.messages['requiredif'] = options.message;
    });

And for propertycvalidator:

$.validator.addMethod('propertycvalidator', function (value, element, parameters) {
			//put your client-side validation logic here
			return true;
		});

		$.validator.unobtrusive.adapters.addBool('propertycvalidator');

And, now we are ready to create our model validator:

		public class MyValidator()
		{
			//Make SomeProperty required. It will be validated on server and client side.
			RuleFor(m => m.SomeProperty)
				.NotEmpty().WithMessage("Some Property is required");
			//SomeOtherProperty will be validated on server side - it is required when PropertyB is true.
			//Client side validation is done by using RequiredIfClientSideValidator and passing dependent property 
			//name to unubtrusive JavaScript validation
			RuleFor(m => m.SomeOtherProperty)
				.NotNull()
				.WithMessage("Some other property is required")
				.When(model => model.PropertyB)
				.SetValidator(new RequiredIfClientSideValidator(
					"Some other property is required",
					"PropertyB",
					true));

			//this will get validated on client side only
			RuleFor(m => m.PropertyC)				
				.SetValidator(
					new ClientSideValidator(
						"Error message",
						"propertycvalidator")); // must be lower case
		}

The last part is adding the attribute to your model:
[Validator(typeof(MyValidator))]
public class YourModel
{
}

Hosting SignalR on GoDaddy in Full Trust

I had some free time recently and decided to learn a truly wonderful library SignalR. SignalR provides the “ability to have your server-side code push content to the connected clients as it happens, in real-time.” It eliminates the extra work of checking browser compatibility with whatever technology you decide to use for pushing the events to the client (WebSockets, EventSource, Long Polling, Forever Frame).

I implemented a simple Chat application using tutorial from Tim Teebken. It worked beautifully on local machine. However, when deployed to GoDaddy my application went down with System.Security.SecurityException. As it turns out, SignalR can run only in Full Trust mode. What I didn’t realize is that to enable full trust you have to explicitly specify Trust Level in Web.Config:

<configuration>
    <system.web>
        <trust level="Full" />
    </system.web>
</configuration>

Once this line was added to the configuration and deployed, my simple Chat client started working.

Bootstrap Font Awesome Icons not working on IE9, IE10

If you are using an older version of Font Awesome you may discover an issue occurring on IE 9 and IE 10, when font is displayed as squares without any text. After some extensive googling the issue was resolved by modifying font-awesome.css and changing the format('eot') to format('embedded-opentype') for the fontawesome-webfont.eot:

from this:

@font-face {
font-family: "FontAwesome";
src: url('../font-awesome/fontawesome-webfont.eot');
src: url('../font-awesome/fontawesome-webfont.eot?#iefix') format('eot'), url('../font-awesome/fontawesome-webfont.woff') format('woff'), url('../font-awesome/fontawesome-webfont.ttf') format('truetype'), url('../font-awesome/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
}

to this:

@font-face {
font-family: "FontAwesome";
src: url('../font-awesome/fontawesome-webfont.eot');
src: url('../font-awesome/fontawesome-webfont.eot?#iefix') format('embedded-opentype'), url('../font-awesome/fontawesome-webfont.woff') format('woff'), url('../font-awesome/fontawesome-webfont.ttf') format('truetype'), url('../font-awesome/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
}

Even better, you can update to the latest version of Font Awesome, which already has this fix.