MVC CORE 2.0.0 run c# code on every page - asp.net-mvc-2

I need to run some c# code each time any page based on _layout.cshtml is viewed. I don't want to put something in every controller.cs file, just something central like you used to have in ASP.NET's MasterPage.cs
Can't get this
Run a method in each request in MVC, C#?
or this
#Html.Action in Asp.Net Core
to run, not sure if it's because they're not CORE 2.0.0, I just get a lot of compilation errors. All I want to do is be able to run some code like this
public class myClass {
public static bool returnTrue() {
return true;
}
}
every time each page is loaded.

You can accomplish this with an action filter
public class GlobalFilter : IActionFilter{
public void OnActionExecuting(ActionExecutingContext context) {
//code here runs before the action method executes
}
public void OnActionExecuted(ActionExecutedContext context) {
//code here runs after the action method executes
}
}
Then in the Startup.cs file in the ConfigureServices method you wire up the ActionFilter like so:
services.AddScoped<GlobalFilter>(); //add it to IoC container.
services.AddMvc().AddMvcOptions(options => {
options.Filters.AddService(typeof(GlobalFilter)); //Tell MVC about it
});
Then you can place code in this ActionFilter which can run before every action method and you can place code in it to run after every action method. See code comments.
Through the context parameter you have access to the Controller, Controller Name, Action Descriptor, Action Name, Request object (Including the path) and so on, so there is lots of info available for you to determine which page you want to execute the code for. I'm not aware of a specific property that will tell you if the page is using _layout.cshtml but you could probably deduce that based on the other properties I mentioned.
Enjoy.

Filter would also work, but the correct way to go in .Net Core is Middleware. You can read more about it here.
If it's something simple as your example, you can go with the first examples on the link like:
app.Use(async (context, next) =>
{
returnTrue();
await next.Invoke();
});
Let me know if it helped!

Related

Struts 2 post back default

In the Struts documentation, it says:
Another common workflow stategy is to first render a page using an alternate method, like input and then have it submit back to the default execute method.
https://struts.apache.org/core-developers/action-configuration.html#post-back-default
How to do it using annotation only? It seems that only the execute() method is called.
In the documentation it's said to render a page can be used an alternate method like input. This means that when you submit a form on the page it can return back with the input result. Usually it happens automatically during validation process if the validation fails or it hasErrors. Then you can submit the form back to the default action's execute method. You don't need to specify a method in the action configuration. Also if you didn't specify the action attribute in the form tag then the same action will execute which was used to render a page.
Configuring actions you can use the same page for success result when rendering a page using GET method and input when POST method is requested.
To use annotations to configure actions mapping you can use a Convention Plugin.
Also note, to map a class method to the action you should put #Action annotation directly on this method rather than on the class.
More detailed explanation and documentation you can find here.
#Namespace("/")
public class ProductAction extends ActionSupport {
public String execute() {
return SUCCESS;
}
#Action(value="product",
results=#Result(location="/product-list.jsp")
)
public String search() {
return SUCCESS;
}
}
Notice, that the method execute is not mapped, so it will not execute. If you need that method execute you should create mapping to it. For this purpose you could place annotation on class or on method execute.

How to create a kentico form that does not store the response

Is there any way in Kentico to have a user submit a form and then email the response but not actually save the answer to the related table?
As mentioned the emails from Kentico rely on the record being written to the DB before they trigger. Furthermore (unless I'm just unlucky) the only values you have access to are those stored in the table. I had thought that maybe you could mark the offending fields as Field without database representation, but sadly, the fields you may want will all be null - so best not to go down that route.
I took a slightly different approach to #trevor-j-fayas in that I used the BizFormItemEvents.Insert.Before event so that there is no trace of any log. It's a short hop from there to make use of an email template to make things look good. So my code looked as follows:
using CMS;
using CMS.DataEngine;
using CMS.EmailEngine;
using System;
[assembly: RegisterModule(typeof(FormGlobalEvents))]
public class FormGlobalEvents : Module
{
public FormGlobalEvents() : base("FormGlobalEvents")
{
}
protected override void OnInit()
{
CMS.OnlineForms.BizFormItemEvents.Insert.Before += Insert_Before;
}
private void Insert_Before(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
var email = new EmailMessage();
email.From = e.Item.GetStringValue("ContactEmail", "null#foo.com");
email.Recipients = "no-reply#foo.com";
email.Subject = "Test from event handler (before save)";
email.PlainTextBody = "test" + DateTime.Now.ToLongTimeString();
EmailSender.SendEmail(email);
e.Cancel();
}
}
To me, it seems cleaner to not insert the record in the first place than delete it, but obviously that autoresponder etc. will only kick in automatically if you do save the record, so the choice is yours and ultimately depends on your preference.
Well, there's a couple different options, but the easiest is to simply delete the record after it's inserted. Use the Global Event Hooks to capture the BizFormItemEvent insert after, if it's your form, then delete it. Below is for Kentico 10:
using CMS;
using CMS.DataEngine;
using CMS.Forums;
using CMS.Helpers;
using CMS.IO;
using System.Net;
using System.Web;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomLoaderModule))]
public class CustomLoaderModule : Module
{
// Module class constructor, the system registers the module under the name "CustomForums"
public CustomLoaderModule()
: base("CustomLoaderModule")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
CMS.OnlineForms.BizFormItemEvents.Insert.After += BizFormItem_Insert_After;
}
private void BizFormItem_Insert_After(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
switch(e.Item.BizFormInfo.FormName)
{
case "YourFormNameHere":
e.Item.Delete();
break;
}
}
}
The other option would be to clone and modify the Online Form Web part to take the information, manually call the email and cancel the insert, but that's a lot of work when this is quicker.
Yes and no. The record is stored before the email notifications and autoresponders are sent out. Your best bet for this is to create a custom global event handler for the form submission(s) using the BizFormItemEvents.Insert.Before. This will call the event before the actual record is stored in the database. You can then cancel out of the event (which will not store the record) and send your email manually.
Handling global events
BizFormItemEvents Events

I want a custom attribute to be fired automatically without writing that on the web api method

I want a custom attribute to be fired automatically without writing that on the web api method.
What is the way I can achieve that?
Let us say for example you have an action filter attribute
public class MyApiActionFilterAttribute : FilterAttribute {
//...
}
With that you can assign it to the class or action depending on how you want it to be used
public class MyApiController : ApiController {
[MyApiActionFilter]
public IHttpActionResult MyAction() {
return Ok();
}
}
This applies to this action only.
But, if you wanted it to be applied on all actions (globally) within the web API, you would need to add it to the configuration.
GlobalConfiguration.Configuration.Filters.Add(new MyApiActionFilterAttribute ());
This is normally done at startup web configuring the web API.
Note that in doing the above, the filter will be applied to all requests.

GWT detect browser refresh in CloseHandler

I have a GWT application and I want to run some code when the user leaves the application to force a logout and remove any data etc.
To do this I am using a CloseHandler and registering it using Window.addCloseHandler.
I have noticed that when the refresh button is clicked the onClose method is run but I have been unable to differentiate this event from a close where the user has closed the browser. If it is a refresh I do not want to do the logout etc, I only want to do this when the user closes the browser/tab or navigates away from the site.
Does anybody know how I can do this?
There is no way to differentiate the 'close' from 'refresh'. But, you can set a cookie that holds the last CloseHandler call time and check, when loading the module, if this time is old enough to clean the information before showing the page.
You can do that with the folowing utility class (BrowserCloseDetector). Here is an example using it on the onModuleLoad.
The test lines:
#Override
public void onModuleLoad() {
if (BrowserCloseDetector.get().wasClosed()) {
GWT.log("Browser was closed.");
}
else {
GWT.log("Refreshing or returning from another page.");
}
}
The utility class:
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
public class BrowserCloseDetector {
private static final String COOKIE = "detector";
private static BrowserCloseDetector instance;
private BrowserCloseDetector() {
Window.addWindowClosingHandler(new Window.ClosingHandler() {
public void onWindowClosing(Window.ClosingEvent closingEvent) {
Cookies.setCookie(COOKIE, "");
}
});
}
public static BrowserCloseDetector get() {
return (instance == null) ? instance = new BrowserCloseDetector() : instance;
}
public boolean wasClosed() {
return Cookies.getCookie(COOKIE) == null;
}
}
Have you tried
<BODY onUnload = "scriptname">
in your gwt hosting/launching html file?
I am thinking that if you defined a map "hash" (i.e. a javascript pseudo hash) in the hosting file and then accessed the "hash" in GWT through Dictionary class, you could update values in that hash as the user progresses through the gwt app. Which means, your programming style would require you to log milestones on the user's progress onto this map.
When the user closes the browser page, the onunload script of the launching html page would be triggered. That script would access the map to figure out what needs to be updated to the server, or what other url to launch.
I am intereted too if someone got a solution (GWT/java side only).
Maybe we can do it with HistoryListerner ?
1-set a flag for your current viewing page.
2-when ClosingHandler event, launch a "timeout" on server-side (for example 10s)
3-if during this time your got a massage from HistoryListerner with the same last flag so it was just a refresh.
of disconnect if timer is over...
Is not a good solution but I think it is easy to do... If someone have a better one...

Issue with MvcContrib TestHelper Fluent Route Testing and Specific HttpVerbs

I'm attempting to use the MvcContrib TestHelper fluent route testing API, but I'm seeing odd behavior. The .WithMethod(HttpVerb) extension method does not seem to be executing as expected. Here's my controller showing (2) actions (identically named) that accept different HttpVerbs:
[HttpGet]
public ActionResult IdentifyUser()
{
return View(new IdentifyUserViewModel());
}
[HttpPost]
public ActionResult IdentifyUser(IdentifyUserInputModel model)
{
return null;
}
And here is the test that should map to the action with the [HttpPost] attribute:
MvcApplication.RegisterRoutes(RouteTable.Routes);
var routeData = "~/public/registration/useridentification/identifyuser"
.WithMethod(HttpVerbs.Post)
.ShouldMapTo<UserIdentificationController>(x => x.IdentifyUser(null));
Even though the POST HttpVerb is specified in my test, it always routes to the HttpGet method. I can even comment out the action accepting HttpPost in my controller and still have the test pass!
Is there something I'm missing here?
It might have to do with how you're registering your routes. I typically create a class that does only that. So before any tests like those above, I make sure I set up my test fixture appropriately.
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
RouteTable.Routes.Clear();
new RouteConfigurator().RegisterRoutes(RouteTable.Routes);
}
My guess is that since the RouteTable handles them statically, you might be running into problems by either not adding, not clearing, or adding too many routes per your test runs.