Caliburn: adding keyboard shortcuts

Posted by Siim on June 28th, 2012

We are creating a desktop app in WFP and using Caliburn.Micro. One thing we needed was to support keyboard shortcuts for almost all the interactions that user can do. Some of them are used globally and some of them depend on the focused control.

When talking about global shortcuts I mean that they can be used anywhere in the current view, they don’t depend on the element in focus. But they are not "globally" global, meaning that when I change the main view that is displayed in the window, shortcuts should be dependent on that view.

Caliburn uses cal:Message.Attach style of syntax to attach different actions for UI events, which can be defined in the XAML. It uses simple string parser to create correct bindings based on the content and it can be easily extended. I needed only to add custom syntax for my shortcuts, like ‘Shortcut Ctrl+F’. I override the parser for that:

public static class ShortcutParser
{
	public static bool CanParse(string triggerText)
	{
		return !string.IsNullOrWhiteSpace(triggerText) && triggerText.Contains("Shortcut");
	}

	public static TriggerBase CreateTrigger(string triggerText)
	{
		var triggerDetail = triggerText
			.Replace("[", string.Empty)
			.Replace("]", string.Empty)
			.Replace("Shortcut", string.Empty)
			.Trim();

		var modKeys = ModifierKeys.None;

		var allKeys = triggerDetail.Split('+');
		var key = (Key)Enum.Parse(typeof(Key), allKeys.Last());

		foreach (var modifierKey in allKeys.Take(allKeys.Count() - 1))
		{
			modKeys |= (ModifierKeys)Enum.Parse(typeof(ModifierKeys), modifierKey);
		}

		var keyBinding = new KeyBinding(new InputBindingTrigger(), key, modKeys);
		var trigger = new InputBindingTrigger { InputBinding = keyBinding };
		return trigger;
	}
}

And it’s attached to caliburn as follows:

var currentParser = Parser.CreateTrigger;
Parser.CreateTrigger = (target, triggerText) => ShortcutParser.CanParse(triggerText)
													? ShortcutParser.CreateTrigger(triggerText)
													: currentParser(target, triggerText);

 

The InputBindingTrigger class is pretty much the same as in this StackOverflow post. I had to modify the OnAttached method, because there are different paths when choosing the element to attach the shortcut.

If element is Focusable, then I can directly associate trigger with target element (like textbox, button etc). But when element isn’t focusable, it means the shortcut is meant to be used globally so I must attach it to the window. When attaching trigger to a window, it means that it is accessible anywhere in the app, whichever view is currently active.

We used the approach where there was only one active view in the conductor and because we needed global shortcuts per active view, I needed to add some code to remove the shortcut binding when the view is unloaded (some other view is activated). So here is revised OnAttached method:

protected override void OnAttached()
{
	if (InputBinding != null)
	{
		InputBinding.Command = this;
		if (AssociatedObject.Focusable)
		{
			AssociatedObject.InputBindings.Add(InputBinding);
		}
		else
		{
			Window window = null;
			AssociatedObject.Loaded += delegate
										{
											window = GetWindow(AssociatedObject);
											if (!window.InputBindings.Contains(InputBinding))
											{
												window.InputBindings.Add(InputBinding);
											}
										};
			AssociatedObject.Unloaded += delegate
											{
												window.InputBindings.Remove(InputBinding);
											};
		}
	}
	base.OnAttached();
}

This allows us to add shortcut binding in XAML with caliburn’s short-style syntax, like:

<UserControl cal:Message.Attach="[Shortcut F6] = [Action SomeAction];
				 [Shortcut F11] = [Action SomeAction2];
				 [Shortcut Ctrl+F] = [Action GlobalSearch]"></UserControl>

<TextBox cal:Message.Attach="[Shortcut Escape] = [Action Clear]" />

There’s only a one thing you need to be aware of. When attaching global shortcuts in caliburn’s way (remember, they are attached to the window), it means that it also uses guard methods to control the execution of the action. And when guard method prevents execution, caliburn by default disables the control associated with the action, in our case the whole window. Unfortunately I haven’t been able to find where to change that behavior, that it wouldn’t disable the control. Workaround is not to use guard methods with such cases and to rely on manual condition checking in actions.

Action based request encoding in ASP.NET MVC

Posted by Siim on June 12th, 2012

Sometimes it’s needed to set different request/response encoding for some of the requests. For example when some third party sends requests (or responses) in some predefined encoding and doesn’t support UTF8, whereas ASP.NET uses UTF8 for all requests and responses by default.

ASP.NET allows us to change that encoding through web.config’s <globalization /> element, like:

<globalization requestEncoding="ISO-8859-1" responseEncoding="ISO-8859-1" />

But this way it affects all the request and that’s not what I want. Luckily, ASP.NET allows web.config file inheritance, by creating separate web.config file in a subfolder or using <location path=””> element in main web.config file.

In case of webforms it’s simple – we need to create location-based configuration for one of our .aspx files. But how to achieve it with MVC you might ask?

Actually, it’s exactly the same. For path part you need to provide full route url to you action. Path attribute doesn’t need to be a physical file or folder, but path in the sense of url. Only drawback is that when changing routes you must remember to change it in the web.config also. And here is the final result, which affects only one action:

<configuration>
...
<location path="path/to/your/actionmethod">
	<system.web>
		<globalization requestEncoding="ISO-8859-1" responseEncoding="ISO-8859-1" />
	</system.web>
</location>
...
</configuration>

WPF AutoCompleteBox–filtering similar items

Posted by Siim on May 30th, 2012

WPF toolkit (from Codeplex) includes a nice control for auto-complete textboxes. It supports also objects as items, not just strings. So we have a concept of selected item. Items can be filtered by simple string comparison (using simple built-in string based filters) or by defining custom filter which can use multiple properties (or whatever you like) to filter items. All these support XAML bindings so it’s all fine.

This allows us to use list of complex items as items source and use different properties for filtering, displaying items in drop-down list and displaying selected item in text box. For example, say we need to select a person from autocomplete and display only person’s last name in text box. But when user chooses person from autocomplete dropdown she wants to see person’s full name (and maybe some other properties) also so she can distinguish between persons. And lets say user wants to search by person’s nicknames also (meaning that when filtering results, we need to check person’s nicknames also). Okay, so far all good. We define custom ItemFilter and create binding for SelectedItem property and when we make a choice we can access selected item.

Problem occurs when there are multiple items with same display values (in our case multiple persons with the same last name). This triggers some weird behaviors on autocomplete side. We can see different persons in drop-down, make a selection and SelectedItem updates accordingly. But when drop-down closes, it looses currently selected item and starts finding it again from the items source based on the text in the text box. Because we have multiple persons with same last name, it selects first one it finds. And selected item is not what user chose, anymore.

Seems it’s quite well known problem based on google, but I didn’t find any solution that I really like. So it was time to dig into the source code. My idea was to create a separate property for my selected item (I call it RealSelectedItem), which behaves similarly to original SelectedItem, so it has also it’s own change events and so forth and I can directly bind to this property. Only problem is to find a proper place to update this property, so I can control when it’s updated and when not.

After digging through source, I found an interesting peace – ISelectionAdapter, which seems to be responsible for selection in drop-down only, sounds like a good place to start. It had events for commiting and cancelling selection, so I can get notifications when selection is changed. I overrode GetSelectionAdapterPart() method (which creates and returns ISelectionAdapter) and attached my methods to Commit and Cancel events when I update my RealSelectedItem property based on the SelectedItem. Full source here:

public class MyAutoCompleteBox : AutoCompleteBox
{
	public object SelectedRealItem
	{
		get { return GetValue(SelectedRealItemProperty); }
		set { SetValue(SelectedRealItemProperty, value); }
	}

	public static readonly DependencyProperty SelectedRealItemProperty =
		DependencyProperty.Register(
			&quot;SelectedRealItem&quot;,
			typeof(object),
			typeof(MyAutoCompleteBox),
			new PropertyMetadata(OnSelectedRealItemPropertyChanged));

	private static void OnSelectedRealItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	{
		var source = d as MyAutoCompleteBox;
		source.SelectedItem = e.NewValue;
		if (e.NewValue == null)
		{
			source.Text = null;
		}

		var removed = new List&lt;object&gt;();
		if (e.OldValue != null)
		{
			removed.Add(e.OldValue);
		}

		var added = new List&lt;object&gt;();
		if (e.NewValue != null)
		{
			added.Add(e.NewValue);
		}

		source.OnRealSelectionChanged(new SelectionChangedEventArgs(SelectionChangedEvent, removed, added));
	}

	protected virtual void OnRealSelectionChanged(SelectionChangedEventArgs e)
	{
		RaiseEvent(e);
	}

	public static readonly RoutedEvent RealSelectionChangedEvent = EventManager.RegisterRoutedEvent(&quot;RealSelectionChanged&quot;, RoutingStrategy.Bubble, typeof(SelectionChangedEventHandler), typeof(MyAutoCompleteBox));

	public event SelectionChangedEventHandler RealSelectionChanged
	{
		add { AddHandler(RealSelectionChangedEvent, value); }
		remove { RemoveHandler(RealSelectionChangedEvent, value); }
	}

	protected override ISelectionAdapter GetSelectionAdapterPart()
	{
		var adapter = base.GetSelectionAdapterPart();
		adapter.Commit += (o, a) =&gt; UpdateSelectedValue(adapter.SelectedItem);
		adapter.Cancel += (o, a) =&gt; UpdateSelectedValue(null);
		return adapter;
	}

	private void UpdateSelectedValue(object value)
	{
		SelectedRealItem = value;
	}
}

Seems to work perfectly fine so far, with or without custom item template for drop down. Though, it doesn’t update RealSelectedItem when user navigates through items (like it is with SelectedItem), but I don’t need that anyway. I only want to know when user made up her mind and selection is made.

For Caliburn I needed to add my own element convention to use x:Name binding convention (actually it was already there, only for SelectedItem property), its basically one-liner (btw Caliburn doesn’t include convention for original SelectedItem either):

ConventionManager.AddElementConvention&lt;AsyncAutoCompleteBox&gt;(AsyncAutoCompleteBox.SelectedRealItemProperty, &quot;SelectedRealItem&quot;, &quot;RealSelectionChanged&quot;)
				.ApplyBinding = (viewModelType, path, property, element, convention) =&gt; ConventionManager.SetBinding(viewModelType, path, property, element, convention);

Minifying CSS & JS in ASP.NET MVC application

Posted by Siim on June 10th, 2011

In my project I have many small JavaScript files containing mostly jQuery plugins. Also there are many CSS files, because I prefer to split my CSS declarations to multiple files based on some context. All this results in many static files that must be loaded in every page load which increases latency.

So I decided to combine multiple files into one single file and also minify it. I looked for some libraries that would get the job done for me and I stick with YUI Compressor which requires Java runtime. I still want to step through readable javascript when I’m developing the app so I decided to combine and minify files only when I’m compiling in release mode, but we will get to that point later on. There were two action I needed to take to achieve this. I needed to modify the web project to include after build action for combining files and to write some kind of extension that’s either loads debuggable source files or compressed files. None of the steps were hard.

Post build step is actually two actions – temporarily combining multiple files into a single file and then minifying that file with YUI Compressor. It gets triggered only when building in a release mode. All the required tools including YUI Compressor are included in VCS so that all dependencies are there when developer checks out code.

<PropertyGroup>
	<yuiCompressor>java -jar ..\..\Tools\yuicompressor\yuicompressor-2.4.2.jar</yuiCompressor>
 </PropertyGroup>
 <Target Name="AfterBuild">
	...
	<CallTarget Targets="Minimize" Condition="'$(Configuration)' == 'Release'" />
 </Target>
 <Target Name="Minimize">
	<GetAssemblyIdentity AssemblyFiles="bin\$(ProjectName).dll">
	  <Output TaskParameter="Assemblies" ItemName="assemblyInfo" />
	</GetAssemblyIdentity>
	<ItemGroup>
	  <JqJsFiles Include="Content\Scripts\jquery.*.js;Content\Scripts\json2.js;" />
	</ItemGroup>
	<ItemGroup>
      <OldVersions Include="Content\Scripts\jq.plugins.min-*.js" />
    </ItemGroup>
	<!-- js Merge and Minimize -->
	<ReadLinesFromFile File="%(JqJsFiles.Identity)">
	  <Output TaskParameter="Lines" ItemName="jqJsLines" />
	</ReadLinesFromFile>
	<WriteLinesToFile File="Content\Scripts\jq.merged.js" Lines="@(jqJsLines)" Overwrite="true" />
	<Delete Files="@(OldVersions)" />
	<Exec Command="$(yuiCompressor) --type js &quot;$(ProjectDir)Content\Scripts\jq.merged.js&quot; -o Content\Scripts\jq.plugins.min-%(assemblyInfo.Version).js --charset utf-8" />
	<Delete Files="Content\Scripts\jq.merged.js" />
</Target>
<PropertyGroup>
	<CopyAllFilesToSingleFolderForPackageDependsOn>
		CollectMinifiedFilesInPackage;
		$(CopyAllFilesToSingleFolderForPackageDependsOn);
	</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="CollectMinifiedFilesInPackage" Condition="'$(Configuration)' == 'Release'">
	<ItemGroup>
	  <_JsFiles Include="Content\Scripts\jq.plugins.min-*.js" />
	  <FilesForPackagingFromProject Include="%(_JsFiles.Identity)">
		<DestinationRelativePath>Content\Scripts\%(Filename)%(Extension)</DestinationRelativePath>
	  </FilesForPackagingFromProject>
	</ItemGroup>
</Target>

As you can see, I include assembly version number (which is generated by build) in the names of the compressed files. This way I can always refer to correct JS files which are accordance with the given assembly. There’s also a target called CopyAllFilesToSingleFolderForPackageDependsOn which is required to include those compressed files in the MSDeploy package because they are not included in the web project and therefore not automatically included.

For the other part I wrote a partial view to load CSS & scripts files based on the configuration. And I use the partial view in my layout files (or wherever I need) to include all required resources. A part of the view:

@if (HttpContext.Current.IsDebuggingEnabled)
{
	@Html.Script("~/Content/Scripts/jquery-1.4.4.js")
	@Html.Script("~/Content/Scripts/jquery-ui-1.8.9.custom.min.js")
	@Html.Script("~/Content/Scripts/jquery.ui.datepicker-en-GB.js?" + DateTime.Now.Ticks)
	@Html.Script("~/Content/Scripts/jquery.selectboxes.js?" + DateTime.Now.Ticks)
	@Html.Script("~/Content/Scripts/jquery.tooltip.js?" + DateTime.Now.Ticks)
	@Html.Script("~/Content/Scripts/json2.js?" + DateTime.Now.Ticks)
}
else
{
	@Html.Script("~/Content/Scripts/jquery-1.4.4.min.js")
	@Html.Script("~/Content/Scripts/jquery-ui-1.8.9.custom.min.js")
	@Html.Script(string.Format("~/Content/Scripts/jq.plugins.min-{0}.js", Html.AssemblyVersion()))
}

Side note: I append the timestamp at the end of the file names to prevent any caching issues in development environment

I make the decision which files to load based on the debug configuration in the web.config, not based on the build configuration in the compile time. I also deploy all the resource files (compressed and original) so I am able to switch between them easily, without recompiling and deploying.

That’s it. No custom out-of-the-solution build scripts needed. And the solution can be also applied to ASP.NET Webforms applications with little modification in including files.

Simplifying ASP.NET MVC controllers with custom action results

Posted by Siim on February 2nd, 2011

When I am developing MVC applications I see that there are some common behavior for certain types of actions (eg. list view, edit view) which means similar code. A common solution to that problem is to create a base controller with that behavior. And that’s also how I tried to solve the problem first. I created base controllers for each view type and their related actions. But it created new problems.

I ended up with a multi-level inheritance tree which made it difficult to track down things. It wasn’t possible to look at the controller and simply say what it is doing. Some of the actions were defined at the upper level that required implementations at the lower level and so on, which created a lot of jumping between classes.
And then there was a common inheritance problem – I needed some behavior from base controller but not all, so I had to implement methods I really didn’t need. Or I needed behavior from multiple base controllers.
Third, it created a big constructors in controllers with all different dependencies required by base controller classes.

I thought about using approach called controllerless actions, but after a little research I found it is too complicated with a given structure. Luckily I can create custom action results that can encapsulate all the logic and data for returning a result for given action. But then I found this post which described separating WHAT of an action result from the HOW. By that I mean that my custom action result contains all the required information to execute an action, but the execution logic is in different object – in an action result invoker I created.

By using this approach I was able to separate all that execution logic from base controllers to separate action invoker. And controller was only responsible for returning a proper action method result with all relevant information based on the input. No repetitive execution logic anymore. For that, I created a base ActionMethodResult which is so called marker base class for my custom action method results.

public abstract class ActionMethodResult : ActionResult
{
	public override void ExecuteResult(ControllerContext context)
	{
		throw new InvalidOperationException("Action should be executed through action invoker");
	}
}

A one simple action method result implementation looks like this. It contains a task to execute and a result to return when task execution was successful and other one for failure cases.

public class TaskActionResult<TEntity> : ActionMethodResult
	where TEntity : IEntity<int>
{
	private readonly Func<ITask<TEntity>> _task;
	private readonly Func<TaskResult<TEntity>, ActionResult> _successContinuation;
	private readonly Func<TaskResult<TEntity>, ActionResult> _failureContinuation;

	public TaskActionResult(Func<ITask<TEntity>> task, Func<TaskResult<TEntity>, ActionResult> successContinuation, Func<TaskResult<TEntity>, ActionResult> failureContinuation)
	{
		_task = task;
		_successContinuation = successContinuation;
		_failureContinuation = failureContinuation;
	}

	public Func<ITask<TEntity>> Task
	{
		get { return _task; }
	}

	public Func<TaskResult<TEntity>, ActionResult> SuccessContinuation
	{
		get { return _successContinuation; }
	}

	public Func<TaskResult<TEntity>, ActionResult> FailureContinuation
	{
		get { return _failureContinuation; }
	}
}

But it’s not the case with all action results. Some of them just take some inputs and invoker decides how to respond to that. The main point is the same – invoker generates some response based on the given action method result in the context of current request. Action invoker for TaskActionResult is like this.

public class TaskActionResultInvoker<TEntity> : ITaskActionMethodResultInvoker<TEntity>
	where TEntity : IEntity<int>
{
	public ActionResult Invoke(TaskActionResult<TEntity> actionResult, ControllerContext controllerContext)
	{
		if (!controllerContext.Controller.ViewData.ModelState.IsValid)
		{
			return actionResult.FailureContinuation(null);
		}

		var result = actionResult.Task().Run();
		if (!result.ValidationResults.IsValid)
		{
			result.ValidationResults.AddToModelState(controllerContext.Controller.ViewData.ModelState);
			return actionResult.FailureContinuation(result);
		}

		return actionResult.SuccessContinuation(result);
	}
}

Then I created a custom IActionInvoker where I overrode the CreateActionResult method to create a proper ActionResult based on my custom action method result. Each of my action invoker held it’s own dependencies so I needed to create a façade for that which got my action invoker as a constructor argument so it could be resolved by my container. The creation of the facades and action invokers is a bit tedious, but it was a compromise I was willing ta make.

public class InjectingActionInvoker : ControllerActionInvoker, IActionMethodResultCreator
{
	private readonly IServiceLocator _serviceLocator;

	public InjectingActionInvoker(IServiceLocator serviceLocator)
	{
		_serviceLocator = serviceLocator;
	}

	protected override ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
	{
		if (IsActionMethodResult(actionReturnValue))
		{
			var result = CreateActionMethodResult(actionReturnValue, controllerContext);

			return IsActionMethodResult(result)
				? CreateActionResult(controllerContext, actionDescriptor, result)
				: result;
		}
		return base.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
	}

	public ActionResult CreateActionMethodResult(object actionReturnValue, ControllerContext controllerContext)
	{
		var wrappedResultType = CreateActionInvokerFacadeType(actionReturnValue);

		var invokerFacade = (IActionMethodResultInvoker)_serviceLocator.Resolve(wrappedResultType);

		return invokerFacade.Invoke(actionReturnValue, controllerContext);
	}

	private static Type CreateActionInvokerFacadeType(object actionReturnValue)
	{
		var actionMethodResultType = actionReturnValue.GetType();

		Type openWrappedType;
		Type wrappedResultType;

		if (actionMethodResultType.IsGenericImplementation(typeof(TaskActionResult<>)))
		{
			openWrappedType = typeof(TaskActionResultInvokerInvokerFacade<>);
			wrappedResultType = openWrappedType.MakeGenericType(actionMethodResultType.GetGenericArguments()[0]);
		}
		// code for other types of action results removed for brevity
		else
		{
			openWrappedType = typeof(ActionMethodResultInvokerFacade<>);
			wrappedResultType = openWrappedType.MakeGenericType(actionMethodResultType);
		}

		return wrappedResultType;
	}
}

Note the recursive call to the CreateActionResult method. It is because my action method results my return other action method results for some execution paths, which in turn need to be invoked with their own type of invokers. So invokers are executed so long as result is “regular” ActionResult which can be executed using ASP.NET MVC built-in behavior. 

Finally, when all hooked up, my controller action looks like this. Simple, clean and without inheritance.

[HttpPost]
public ActionResult Edit(int id, ViewModel item)
{
	item.Id = id;

	return new TaskActionResult<Entity>(
		() => _taskFactory.ForSave(() => CreateEntityFromViewModel(item)),
		success => SaveSuccessResult(success, "Task executed!"),
		SaveFailureResult);
}

Now I’m able to create much more simple controllers in the maintenance point of view, they are better to follow. It also improved testability. Because in my opinion, inheritance is pain in the butt regarding testing. This approach allowed me to easily test the result of the controller action (which is basically a plain data) separately from the execution of that result. Which I can do in an isolation compared to the approach when I was using controller inheritance which also resulted in some sort of tests inheritance.

Storing files and metadata with NHibernate

Posted by Siim on September 21st, 2010

Now and then there comes a need to save some documents to the database also, along with the other information stored there already. It’s not a big deal to save some additional files to the database, especially when it’s not the main purpose of the application, just some extra. So no need for different storage mechanism.

This time I’m using NHibernate and I thought how I should structure tables and write mappings so that files data gets loaded only then when I really need it (eg. downloading a file). I also save some metadata about the file, some if it has business meaning, some of it doesn’t.

Database

I came up with the following simple schema:

clip_image001

I can load all the related meta-info about the file easily without touching the real content. That kind of schema also allows us to put FILE_DATA table to a different file group in MS SQL Server, so physically it can be located on other drive or partition whereas files metadata is located with our other tables.

Mappings

But this is only database side, there are also NHibernate mappings we have to work on. From NHibernate point of view, it’s not one-to-one relation but more like an one-to-many relation, meaning that File may have 0 or more FileData objects. So internally I mapped it like so, but to the outside I exposed it like one-to-one. I am using FluentNhibernate and here are my mappings for that:

public class FileMap : ClassMap<File>
{
	public FileMap()
	{
		DiscriminateSubClassesOnColumn("FILE_TYPE");

		Id(x => x.Id);
		Map(x => x.Type, "FILE_TYPE")
			.ReadOnly();
		Map(x => x.Name);
		Map(x => x.ContentType);

		HasMany<FileData>(Reveal.Member<File>("_files"))
			.Access.Field()
			.Cascade.AllDeleteOrphan()
			.Inverse();
	}
}

public class FileDataMap : ClassMap<FileData>
{
	public FileDataMap()
	{
		Id(x => x.Id);
		Map(x => x.Content);
		References(x => x.File);
	}
}

And related objects:

public abstract class File : IntegerIdentityEntity
{
	private IList<FileData> _files;

	protected File()
	{
		_files = new List<FileData>();
	}

	protected virtual IList<FileData> Files
	{
		get { return _files; }
	}

	protected virtual FileData FileData
	{
		get { return Files.SingleOrDefault(); }
	}

	public virtual string Type { get; protected set; }

	public virtual string Name { get; set; }

	public virtual string Number { get; set; }

	public virtual string ContentType { get; set; }

	public virtual byte[] Data
	{
		get
		{
			return FileData != null ? FileData.Content : null;
		}
		set
		{
			if (FileData != null && value == null)
			{
				FileData.File = null;
				Files.Remove(FileData);
			}
			else if(FileData != null)
			{
				FileData.Content = value;
			}
			else if(value != null)
			{
				var dataFile = new FileData {File = this, Content = value};
				Files.Add(dataFile);
			}
		}
	}
}

public class FileData : IntegerIdentityEntity,
{
	public virtual File File { get; set; }

	public virtual byte[] Content { get; set; }
}

As you can see, externally there is only one object – File, with property Data which returns the contents of the file as a byte array. Internally it is stored in the FileData collection because it’s the natural way how NHibernate handles such scenarios but that doesn’t mean we must always expose it as collection.

Conclusion

This approach allows to store files and their metadata in a database in a simple way, without adding any extra overload to fetching when it’s not necessary. From a database perspective it don’t add any extra constraints either, because we can put data table to a different partition so keeping the size of the main database reasonable.

ASP.NET MVC RenderAction with action method overloads

Posted by Siim on September 5th, 2010

In ASP.NET MVC, every controller method which is public and not marked with NonAction attribute is considered as an action. And action name is the same as method name. But you can also provide ActionName attribute with specified action name. There is also different attributes to constrain actions to handle only specified HTTP methods (GET, POST, PUT etc). All that information is used when finding which controller method to execute.

So, when technically (in a sense of C#) you can create many method overloads for a controller method, you end up with runtime exception when you don’t further restrain those actions. For example, consider following controller:

public class ProductController : Controller
{
	public ActionResult Edit(int id)
	{
		return View("Edit");
	}

	public ActionResult Edit(int id, ProductItem item)
	{
		return View("EditPost");
	}
}

public class ProductItem
{
	public int Id { get; set; }

	public string Name { get; set; }
}

When executing Edit action, MVC don’t know which method overload to execute, because current route could be handled by both of the Edit methods. But when decorating first method with HttpGet attribute and the second with HttpPost attribute, it works well.

Now, the trouble comes when you execute one of such methods from the view with RenderAtion method. Lets say you have two controllers:

public class ProductController : Controller
{
	public ActionResult Edit(int id)
	{
		return View("Edit");
	}

	[HttpPost]
	public ActionResult Edit(int id, ProductItem item)
	{
		return View("EditPost");
	}
}

public class ProductDetailController : Controller
{
	public ActionResult Edit(int id)
	{
		return View("EditDetail");
	}

	[HttpPost]
	public ActionResult Edit(int id, ProductDetailItem item)
	{
		return View("EditDetailPost");
	}
}

public class ProductDetailItem
{
	public string Type { get; set; }
}

public class ProductItem
{
	public int Id { get; set; }

	public string Name { get; set; }
}

ProductController is used to display product form view. On that form, I also call RenderAction to render Edit method on the ProductDetailController which displays some product sub-detail form. When executing first ProductController.Edit method, all works fine. When I submit product form, then the second Edit method is executed (because it handles POST requests).

At first, it looked like some weird behavior. But after when I gave a thought how MVC resolves which action method to execute, it all works out. It’s because RenderAction uses the same algorithm to resolve actions as a regular action link. So pay attention when using same pattern with controllers and actions.


Copyright © 2007 Siim Viikman's blog.