I'm working on a multi language web site and I need to set language first and then shows the page in that exact language using Resources files.
I used two index action like this :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Globalization;
using global_vrf.GeoIpService;
namespace global_vrf.Controllers
{
public class HomeController : Controller
{
public ActionResult Index(string language)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
return View();
}
public ActionResult Index()
{
string language="en-us";
return View(language);
}
}
}
but when I run the page, I have this Error:
The current request for action 'Index' on controller type
'HomeController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Index(System.String) on type
global_vrf.Controllers.HomeController System.Web.Mvc.ActionResult
Index() on type global_vrf.Controllers.HomeController
Just make one method:
namespace global_vrf.Controllers
{
public class HomeController : Controller
{
public ActionResult Index(string language)
{
if(String.IsNullOrWhiteSpace(language))
{
string language="en-us";
}
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
return View();
}
}
}
You can't make 2 methods becouse string could be null.
[HttpPost]
public ActionResult Index(string language)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
return View();
}
[HttpGet]
public ActionResult Index()
{
string language="en-us";
return View(language);
}
Related
I have a Xunit test class for a MVC:
using System;
using Xunit;
using Home.Controllers;
using Microsoft.AspNetCore.Mvc;
using Tester.Models;
using Xunit.Abstractions;
namespace ClassLibrary1
{
public class Class1
{
[Fact]
public void CreateinController()
{
HomeController c = new HomeController();
var result = c.Create();
//result moet een view zijn
var viewResult = Assert.IsType<ViewResult>(result);
//Juiste redirection
var result2 = c.Create(null);
var redirectToActionResult =
Assert.IsType<RedirectToActionResult>(result2);
Assert.Equal("Home", redirectToActionResult.ControllerName);
Assert.Equal("BoekingVerwerken", redirectToActionResult.ActionName);
}
}
}
Whenever I run the test the ActionName passes the test because it actually contains the value. But the ControllerName seems to be NULL valued, why is this?
When the Action has a value why wouldn't the Controller have one? Should I put the controller in the RTA?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Tester.Models;
namespace Home.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(HotelBoeking boeking)
{
return RedirectToAction("BoekingVerwerken", boeking);
}
[HttpGet]
public IActionResult BoekingVerwerken(HotelBoeking boeking)
{
return View(boeking);
}
}
}
If you take a look at the Controller.cs source code, you will see that RedirectToAction returns a RedirectToRouteResult type, not a RedirectToActionResult type.
As you can see from the source code of RedirectToRouteResult.cs, you can get the controller name from the RouteValues property. There is no ControllerName property on this type.
var redirectToRouteResult =
Assert.IsType<RedirectToRouteResult>(result2);
Assert.Equal("Home", redirectToRouteResult.RouteValues["controller"]);
I am not entirely sure the syntax for XUnit is correct, as I don't work with it much, but you should take away from this that because MVC is open source that questions like this one can be easily answered by inspecting the source code.
My session becomes null when I redirect to another controller's Action, what should I do?
With regards to the comment you posted me, here is what I was thinking. In the Controller where you need the session use something similar to this:
//Controller A
public class TheController : Controller
{
public ActionResult Index(){
Session["yourSession"] = "Hello World";
return View();
}
}
//Controller B
public class MyController : Controller
{
string textString;
protected override void OnActionExecuting(ActionExecutingContext ctx)
{
base.OnActionExecuting(ctx);
textString = ctx.HttpContext.Session["yourSession"].ToString();
}
public ActionResult Index(){
string currentText = textString;
return View();
}
}
I tested the suggestion from (http://stackoverflow.com/questions/889516/session-null-in-asp-net-mvc-controller-constructors), and the contents of the session were available.
You have to create a unique base controller with a session property, then all controllers within your project will inherit from that BaseController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MonitoringCSP.Controllers
{
//[AllowAnonymous]
//[Authorize(Roles = "admin")]
public class BaseController : Controller
{
private HttpSessionStateBase _session;
protected HttpSessionStateBase CrossControllerSession
{
get
{
if (_session == null) _session = Session;
return _session;
}
set {
_session = Session;
}
}
}
}
Usage sample
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using MonitoringCSP.Models;
namespace MonitoringCSP.Controllers
{
[AllowAnonymous]
public class AccountController : BaseController
{
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
/*session*/
CrossControllerSession["UserName"] = User.Identity.Name;
/*end session*/
return RedirectToAction("someAction");
}
}
}
I realized that I was clearing and destroying all sessions prior to setting the new session on login like this
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Session.Abandon();
Session.Clear();
When I removed these lines, everything started working like #Clayton said, so I removed these lines and replaced it with Session.Remove('sessionvariablename'), I am still not sure what issue were the above lines causing, but my code started working.
Make sure your controller does not have this attribute set on it:
[SessionState(SessionStateBehavior.Disabled)]
I having trouble getting a value to my base controller. All I would like to do is have my base controller pick up an ID from an ActionLink?
Link
<%= Html.ActionLink("About Us", "About", new { SectionId = 1 })%>
Base Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.Controllers
{
public class SectionController : Controller
{
//
// GET: /Section/
public SectionController(int SectionId)
{
if (SectionId == 1)
{
ViewData["Message"] = "GOT AN ID";
}
else
{
ViewData["Message"] = "NO ID";
}
}
}
}
Home Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.Controllers
{
[HandleError]
public class HomeController : SectionController
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View();
}
}
}
Solution so far
ActionLink
<%= Html.ActionLink("About Us", "About", new { SectionId = 1})%>
SectionAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.ActionFilters
{
public class SectionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Actions have sectionId parameter
object SectionId = filterContext.ActionParameters.FirstOrDefault(x => x.Key == "SectionId").Value;
if (SectionId != null && (int)SectionId == 1)
{
filterContext.Controller.ViewData["Message"] = "GOT AN ID";
}
else
{
filterContext.Controller.ViewData["Message"] = "NO ID";
}
}
}
}
SectionController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Website.ActionFilters;
namespace Website.Controllers
{
[Section]
public class SectionController : Controller
{
}
}
View
<%= Html.Encode(ViewData["Message"]) %>
Your code won't work. Instead you should define OnActionExecuting method in base controller, where you get actual sectionId from route data and set ViewData accordingly. Try something like this (not tested):
public class SectionController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Actions have no sectionId parameter - look for it in querystring
string SectionId = filterContext.HttpContext.Request.QueryString["sectionId"];
int sId;
if (int.TryParse(SectionId, out sId) && sID == 1)
{
filterContext.Controller.ViewData["Message"] = "GOT AN ID";
}
else
{
filterContext.Controller.ViewData["Message"] = "NO ID";
}
}
}
Updated:
You can move this out from controller and create ActionFilter. It is very simple:
public class SectionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Actions have sectionId parameter
object SectionId = filterContext.ActionParameters
.FirstOrDefault(x => x.Key == "sectionId").Value;
if (SectionId != null && (int)SectionID == 1)
{
filterContext.Controller.ViewData["Message"] = "GOT AN ID";
}
else
{
filterContext.Controller.ViewData["Message"] = "NO ID";
}
}
}
...
[Section]
public class SectionController : Controller {
or
[HandleError, Section]
public class HomeController : SectionController {
A constructor of a base controller is not typically the place where common code is placed. You usually create a filter for common code. If you decorate the base controller with this filter attribute, then all inheriting controllers use that filter.
hi i am trying to create a custom attribute for my MVC application so that i can call [CheckLogin] this is to check my cookie as i am not using forms authentification.
i have created a class CheckLogin and this is in my App_Code folder and the code is as follows:
using System.Web.Mvc;
using System.Attributes;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Web;
using System;
namespace corian_MVC.Controllers
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CheckLoginAttribute : FilterAttribute, IAuthorizationFilter
{
public CheckLoginAttribute() {}
public void OnAuthorization(AuthorizationContext filterContext)
{
// TODO: perform your cookie checks
if (!userIsAuthenticated)
{
filterContext.Result = new RedirectResult(string.Format(
"/Admin/Login",
filterContext.HttpContext.Request.Url.AbsoluteUri));
}
}
}
}
what it does is not important here, the problem is i cant get my code to recognise this attribute if it is one in the first place, also how do i redirect to action if the login is failed ????
many thanks
my admin class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace corian_MVC.Controllers
{
[HandleError]
public class AdminController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
//check login is not banned
if ((int)Session["LoginCount"] >= 3) RedirectToAction("TooMany");
return View();
}
public ActionResult Fraud()
{
Session["LoginCount"] = 3;
return View();
}
public ActionResult TooMany()
{
return View();
}
[CheckLogin]
public ActionResult Welcome()
{
return View();
}
private void Createcookie()
{
}
}
}
This scenario is best handled by implementing an IAuthorizationFilter.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
public class CheckLoginAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
// TODO: perform your cookie checks
if (!userIsAuthenticated)
{
filterContext.Result = new RedirectResult(string.Format(
"/loginUrl?ReturnUrl={0}",
filterContext.HttpContext.Request.Url.AbsoluteUri));
}
}
}
Then you can apply this attribute either at the controller level or at some particular actions.
By the way do you have any particular reason for not using the built-in FormsAuthentication?
Include .cs file with your attribute to the solution. Just placing it "near default.aspx" is not enough.
I have a base controller class and I would like to pass a Message from the Base class to all controllers and for that message to be available to all views.
I've created a basic version below...
Section Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.Controllers
{
public class SectionController : Controller
{
//
// GET: /Section/
public ActionResult Section()
{
ViewData["Message"] = "THIS IS A TEST";
return View();
}
}
}
Home Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.Controllers
{
public class HomeController : SectionController
{
public ActionResult Index()
{
return View();
}
}
}
View
<%= Html.Encode(ViewData["Message"]) %>
I know I can do this in the home controller but I'm just testing at the mo.
I'm not getting any errors with the above but I'm also not displaying the message on my view?
I'm using this tutorial http://www.asp.net/LEARN/mvc/tutorial-13-cs.aspx The Good Solution part, if that helps.
Think I've got it working now used the code below on my sectionController...
namespace Website.Controllers
{
public class SectionController : Controller
{
//
// GET: /Section/
public SectionController()
{
ViewData["Message"] = "THIS IS A TEST";
//return View();
}
}
}
Is this an ok solution?
You're setting your ViewData in the Section action method of your base controller, do you actually want to be setting it in the constructor of your base controller?
public SectionController()
{
ViewData["Message"] = "THIS IS A TEST";
}
HomeController.Index isn't calling SectionController.Section.
Because none of the requests are mapped to action "Section" in SectionController. If you mapped a request like domain/Section/Section, you would see your message in your view (Assuming that you are using default routing and have a view named "Section").
What you need to do is, placing your message into the viewdata on a method that runs every time an action is run. You can do it in OnActionExecuting like:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewData["Message"] = "THIS IS A TEST";
base.OnActionExecuting(filterContext);
}
in the SectionController.