Action Invoker
Action Invoker’s role is to call suitable action
depending upon the request directed by the controller. Controller consists of
different actions with different return types. There may be two or more
overloads of same actions inside the controller. The nature of those actions
may be different. Some actions are targeted for the GET request and some for
the POST request. Some actions may be disqualified as a valid action. It’s duty
of the action invoker to look after all these aspects before diverting the action
call. We gave little introduction about Action Invoker in “Controller Factory
and Action Invoker Part 1”. Now we discuss about the extensibility and
customizability of the action invoker.
Custom Action Invoker
Custom action invokers are rarely used unless we are
writing our own rules. Sometimes afar from other native request, we may come up
with our own action selector. Action selectors are attributes applied to any
action. These selectors convey special kind of desired behavior such as GET,
POST or PUT. We can customize action selector for our own purpose.
For example let us assume that there are two way to
validate the price of the purchased item. A store keeper can directly input the
price of the goods or he/she may use bar code reader. We can imagine that we
have two actions based on the nature of input. A store keeper’s typed input can
simply use POST request assisted action. However, for barcode reader
integration, we need a separate custom action selector. The action for barcode
reader contains the nifty codes to decode the price from an input image. Action
invoker is the exact location, where we can find smooth fitting for such codes.
Based on the nature of request, we can call correct override from the available
action name. However, for pure custom action invoker their perspective of implementation
is very hard to pin point.
To be useful as a custom action invoker, our
custom class must implement the interface “IActionInvoker”. This interface is responsible for invoking
the action rather than relying on the default configuration. The skeletal code
for this interface is as listed below:-
using System;
namespace
System.Web.Mvc
{
// Summary:
// Defines the contract for an action
invoker, which is used to invoke an action
// in response to an HTTP request.
public interface IActionInvoker
{
// Summary:
// Invokes the specified action by using the
specified controller context.
//
//
Parameters:
// controllerContext:
// The controller context.
//
// actionName:
// The name of the action.
//
// Returns:
// true if the action was found; otherwise,
false.
bool
InvokeAction(ControllerContext
controllerContext, string actionName);
}
}
Listing 1:- Skeletal code for the interface “IActionInvoker”
This interface defines a method named “InvokeAction” which is responsible for invoking the
custom behavior. The first parameter to this method is “controllerContext” of type “ControllerContext” which gives us access over the current or
requesting controller context. We can easily access controller specific
property through this parameter. The second parameter is “actionName” of type “string” which represents the name of the requested
action. This value can alternatively be obtained from the route value
dictionary through route data with the help of requesting controller context.
The return type of this method is boolean type. True value indicates that the
request has been processed. False value indicates the inability to process the
request.
We are going to use custom action invoker to
imitate the POST and GET request. In GET assisted request, we are rendering a
form which prompts for user input. In POST assisted request, we are addressing
a hello message to the users along with their entered inputs. We could have
done this just by using “[HttpPost]” and “[HttpGet]” attribute with the action methods, and
rendering a suitable view for every user request.
To proceed with the example of custom action
invoker, we create a class “MyActionInvoker” inside the “infrastructure” folder of the MVC
project. We implement interface “IActionInvoker” for this class. Inside the “InvokeAction”, we check for the request type and the
action name. Depending upon the request type and the action name, suitable
action is carried out. The code below lists out the “MyActionInvoker” class.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Web;
using
System.Web.Mvc;
using
ControllerExtensibility.Models;
using System.Text;
namespace
ControllerExtensibility.Infrastructure
{
public class MyActionInvoker
: IActionInvoker
{
#region IActionInvoker Members
public bool InvokeAction(ControllerContext
controllerContext, string actionName)
{
if
(controllerContext.HttpContext.Request.RequestType == "GET"
&& actionName == "item")
{
StringBuilder
view = new StringBuilder();
view.Append("<script type='text/javascript'
src='/Scripts/jquery-1.5.1.min.js'></script>");
view.Append("<form id='form' method='post' action='/test/item'>");
view.Append("<script type='text/javascript'>");
view.Append("$(document).ready(function () {");
view.Append("$('#submit').click(function () {");
view.Append("var name; var attribs;");
view.Append("name=$('#name').val();");
view.Append("attribs=$('#form').attr('action');");
view.Append("attribs=attribs+'?name='+name;");
view.Append("$('#form').attr('action',attribs);");
view.Append(" })");
view.Append(" })");
view.Append("</script>");
view.Append("<p>Your Name:</p>");
view.Append("<input id='name' type='text' value=''
name='name' id='name'>");
view.Append("<input type='submit' value='submit'
name='submit' id='submit'></form>");
controllerContext.HttpContext.Response.Write(view.ToString());
return
true;
}
else if
(controllerContext.HttpContext.Request.RequestType == "POST"
&& actionName == "item")
{
string
name=string.Empty;
if
(controllerContext.HttpContext.Request.QueryString["name"]
!= null)
{
name =
controllerContext.HttpContext.Request.QueryString["name"];
}
controllerContext.HttpContext.Response.Write("<p>Hello:<b>"
+ name + "</b></p>");
return
true;
}
else
{
return false;
}
}
#endregion
}
}
Listing 2:-“ MyActionInvoker” class
We checked the request type by the help of
HTTP context available through the Controller Context. For the “GET” request
which targets the “item” action, we rendered an HTML page. The html was
constructed by help of .net class “StringBuilder”. We have appended both JQuery/Javascript
and HTML code within the “StringBuilder” instance. By JQuery/javascript, we extracted an attribute “action” of the
“form” tag. To this attribute value, we appended the value entered inside the
textbox as a query string. All this is carried out on the click event of the
“submit” button. After successful completion of client event, form is submitted
along with updated value of the “action” attribute. Frankly, this is not an
appropriate way to code as you will observe compile time bug only during run
time. At compile time our hectic code is nothing but a string value. During the
“POST” request for the “item” action, we checked for query string “name”. The
“name” value which was submitted in the previous request is rendered here.
Similar to previous case, we rendered HTML by outputting the HTML content
directly from HTTP Context response’s write method.
To take care of these actions, we add a “Test” controller (regular MVC
controller). Below code lists the test controller.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Web;
using
System.Web.Mvc;
using
ControllerExtensibility.Infrastructure;
using
ControllerExtensibility.Models;
using
System.Web.Routing;
namespace
ControllerExtensibility.Controllers
{
public class TestController
: Controller
{
//
// GET: /Test/
public
TestController()
{
this.ActionInvoker
= new MyActionInvoker();
}
}
}
Listing 3:-“Test” controller
During the instantiation of the “Test” controller i.e. inside the “Test”
controller constructor, we set the “ActionInvoker” property of this controller to the
newly created instance of “MyActionInvoker”.
When we run the
project at this point, we can see the following outputs
Figure 1:- redirecting to the URL
“/test/item”
We are accessing the “GET” request portion of
custom action invoker when we redirect to this particular URL “/test/item”.
When we fill up the form
and click of submit/press enter,
Figure 2:- Upon submitting the form
Default Action Invoker
If we had directly used “GET” and “POST”
attributes along with action methods and views in the test controller, then it
would be one kind of default implementation. We are using this default action
invoker knowingly or unknowingly. For insight knowledge about functionality of
the default action invoker, we will explore default custom action invoker. To
make our class as a default implementation of the action invoker, we must
derive it from “ControllerActionInvoker”. “ControllerActionInvoker” is the action invoker used by every regular
MVC controller. If we check the definition of this default class, we can see
numerous virtual functions. We can override them with our own custom logics. “ControllerActionInvoker” implements “IActionInvoker” which is absolutely obvious.
With the help of default action invoker, we
are going to replicate above example of custom action invoker. We are going to
implement views instead of writing the HTML content directly. This makes our HTML
code manageable, easily interpretable, and maintainable.
While deriving from a class and overriding any
function, we must provide fall back support for other methods which are beyond
our interest. Whereas for “POST” and “GET” request for “item” action, we
implement our own logic. For this purpose we are overriding the method “InvokeAction”. We have already dealt with this method in
custom action invoker of type “IActionInvoker”. The return type and parameters of this method
has already been discussed in the custom action invoker segment.
We create class “MyDefaultActionInvoker” within the “infrastructure” folder of our application. “MyDefaultActionInvoker” class is derived from “ControllerActionInvoker”. The code listed below shows the same:-
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Web;
using
System.Web.Mvc;
using
System.Web.UI.WebControls;
namespace
ControllerExtensibility.Infrastructure
{
public class MyDefaultActionInvoker
: ControllerActionInvoker
{
public override bool
InvokeAction(System.Web.Mvc.ControllerContext
controllerContext, string actionName)
{
if
(controllerContext.HttpContext.Request.RequestType == "GET"
&& actionName == "item")
{
ViewResult
viewResult = new ViewResult();
viewResult.View =
viewResult.ViewEngineCollection.FindView(controllerContext, "ItemGet", null).View;
InvokeActionResult(controllerContext, viewResult);
return
true;
}
else
if
(controllerContext.HttpContext.Request.RequestType == "POST"
&& actionName == "item")
{
ViewResult
viewResult = new ViewResult();
viewResult.View = viewResult.ViewEngineCollection.FindView(controllerContext,
"ItemPost", null).View;
InvokeActionResult(controllerContext, viewResult);
return
true;
}
else
{
return
base.InvokeAction(controllerContext,
actionName);
}
}
}
}
Listing 4:-“ MyDefaultActionInvoker” class
Within the “InvokeAction”, as in previous
case, we’ve split the logic into two parts for “GET” and “POST” request type
for the action “item”. An instance of type “ViewResult” is created in both portions. The view property of this instant is set to
the view property of the result returned by “FindView” method. This find view method searches over the collection of the view
from “ViewEngineCollection”. This collection
comprises of all the views of our application. The parameters to “FindView” are the current controller context, the name of the view and the name of
the master page. For the “GET” request we search for the view named “ItemGet.cshtml”
and for the “POST” request we search for the view named “ItemPost.cshtml”. These views are set as “ActionResult” (“ViewResult” are derived from “ActionResult”) by calling
method “InvokeActionResult”. The controller context
and the view result instance are passed as parameters to this method. If the
request is for any action other than “item”, we will call the base class method
“InvokeAction”. This way we will be supporting fall back architecture.
We make minor change in the “test” controller i.e. by updating reference to
action invoker to “MyDefaultActionInvoker” class instance. The code for the “test” controller is as listed below:-
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Web;
using
System.Web.Mvc;
using
ControllerExtensibility.Infrastructure;
using
ControllerExtensibility.Models;
using
System.Web.Routing;
namespace
ControllerExtensibility.Controllers
{
public class TestController
: Controller
{
//
// GET: /Test/
public
TestController()
{
this.ActionInvoker
= new MyDefaultActionInvoker();
}
}
}
Listing 5:- “Test” controller
The newly added views “ItemGet.cshtml” and “ItemPost.cshtml” in
“/views/test” path is as listed below:-
@{
ViewBag.Title = "ItemGet";
}
<script type="text/javascript">
$(document).ready(function
() {
$("#submit").click(function () {
var
name;
var
attribs;
name = $('#name').val();
attribs = $('#form').attr('action');
attribs = attribs + '?name=' + name;
$('#form').attr('action', attribs);
})
})
</script>
@using (Html.BeginForm("item",
"test", FormMethod.Post,
new { id = "form"
}))
{
<p>
Your Name:</p>
<input id='name' type='text' value='' name='name' id='name' />
<input type='submit' value='submit' name='submit' id='submit' />
}
Listing 6:-“ItemGet.cshtml”
@{
ViewBag.Title = "ItemPost";
}
@{string name = string.Empty;}
@if (HttpContext.Current.Request.QueryString["name"] != null)
{
name = HttpContext.Current.Request.QueryString["name"].ToString();
}
<p>Hello:<b>@name</b>
Listing 7:-“ItemPost.cshtml”
The HTML code in
“ItemGet.cshtml” is proper than the preceding one in the custom action invoker
class. JQuery/Javascript is properly placed along with use of razor “Html”
helper methods.
When we run the
project, we can see the following outputs
Figure 3:- Redirecting to URL “/test/item”
Figure 4:- After submitting or posting the request
The both outputs in the custom and the default implementation looks
similar. What we need to put inside our head is that for custom implementation,
everything is hand written. While for default implementation, a view is used
instead. Nobody can tell the difference by only observing the screenshots. Even
the URL is same. Everything remains unchanged except the internal structure.
This is the flexibility of the MVC framework. We can get the job done without
letting others know about the changes we made. No can tell that we switched from
the custom action invoker to the default action invoker. We have maintained the
integrity of our application throughout the project. Only we know how much
vital is our change, but to the outside world they don’t feel the difference.
Discipline of the software engineering/development is to settle on the fact
what other assumes us to be and still be able to keep our achievement to
ourselves. We are rather happy and better off with clients who does feasibility
research on our behalf.
Nice post Narendra.
ReplyDeleteASP.NET MVC Training | MVC Online Training | MVC Training | ASP.NET MVC Training in Chennai | ASP.NET MVC 6 Training | Dot Net Training in Chennai
ReplyDelete.Net MVC Training | ASP.NET MVC Online Training | C# MVC Training | ASP.NET MVC Training in Chennai | Online ASP.NET MVC 6 Training | Dot Net Training in Chennai
Nice and Easy Explanation.
ReplyDeleteVery Needful.
Post some more .....
Thanks
Ankur
Really you have done great job,There are may person searching about that now they will find enough resources by your post
ReplyDeleteBest Devops Training in pune
Best Devops Training institute in Chennai
Thank you for allowing me to read it, welcome to the next in a recent article. And thanks for sharing the nice article, keep posting or updating news article.
ReplyDeleteSelenium training in Chennai
Selenium training in Bangalore
Selenium training in Pune
Selenium Online training
I have read a few of the articles on your website now, and I really like your style of blogging. I added it to my favourites blog site list and will be checking back soon.
ReplyDeletepython Training in Pune
python Training in Chennai
python Training in Bangalore
Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
ReplyDeleteDevOps Training | Certification in Chennai | DevOps Training | Certification in anna nagar | DevOps Training | Certification in omr | DevOps Training | Certification in porur | DevOps Training | Certification in tambaram | DevOps Training | Certification in velachery
I read this blog is very informative content. thank you so much your article.
ReplyDeletePython Training in Chennai
Python Training in Training
Python Training in Bangalore
Python Hyderabad
Python Training in Coimbatore
Thanks for sharing such a amazing article,it was really useful and i would like to thank you for this article.Am very much intrested to learn new thing like this.keep posting like this valuable information.amazon web services aws training in chennai
ReplyDeletemicrosoft azure training in chennai
workday training in chennai
android-training-in chennai
ios training in chennai
this article is very interesting to read.
ReplyDeleteu
instagram takipçi satın al
ReplyDeleteaşk kitapları
tiktok takipçi satın al
instagram beğeni satın al
youtube abone satın al
twitter takipçi satın al
tiktok beğeni satın al
tiktok izlenme satın al
twitter takipçi satın al
tiktok takipçi satın al
youtube abone satın al
tiktok beğeni satın al
instagram beğeni satın al
trend topic satın al
trend topic satın al
youtube abone satın al
instagram takipçi satın al
beğeni satın al
tiktok izlenme satın al
sms onay
youtube izlenme satın al
tiktok beğeni satın al
sms onay
sms onay
perde modelleri
instagram takipçi satın al
takipçi satın al
tiktok jeton hilesi
instagram takipçi satın al
pubg uc satın al
sultanbet
marsbahis
betboo
betboo
betboo
Great post. Thanks for sharing such a useful blog.
ReplyDeleteSpoken english classes in t nagar
Spoken English Classes in Chennai
This post is so interactive and informative.keep update more information...
ReplyDeleteSpoken English Classes in Tambaram
Spoken English Classes in Chennai
Great post. keep sharing such a worthy information.
ReplyDeleteSEO Training in Chennai
SEO Course
yeni perde modelleri
ReplyDeleteNumara onay
mobil ödeme bozdurma
nft nasıl alınır
ankara evden eve nakliyat
Trafik Sigortası
Dedektör
web sitesi kurma
aşk kitapları
smm panel
ReplyDeletesmm panel
İŞ İLANLARI BLOG
İnstagram takipçi satın al
hirdavatciburada.com
WWW.BEYAZESYATEKNİKSERVİSİ.COM.TR
Servis
tiktok jeton hilesi
yurtdışı kargo
ReplyDeleteen son çıkan perde modelleri
özel ambulans
minecraft premium
uc satın al
en son çıkan perde modelleri
nft nasıl alınır
lisans satın al