How to access BetterCMS Admin page - asp.net-mvc

I successfully setup BetterCMS in my ASP.NET MVC application with the help of following link:
http://www.devbridge.com/articles/better-cms-for-developers/
I can view following page now:
How I can see Admin section now?
Tx.

I'm sure you figured this out by now, but to make this post useful for others all you need to do is put /login after your localhost adress.
like this: localhost:50720/login

You recheck file at : "App_Start/RouteConfig.cs". You config same below :`
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//);
}`

Just comment the "Route config" method in global.ascx.cs file.
similarly to do for the below code in RouteConfig file,comment the register path.
To get Admin settings , just the below model in your main layout page
#{
Layout = "~/Areas/bcms-Root/Views/Shared/BaseLayout.cshtml";
}

Replace your Global.asax with the below code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using System.Security.Principal;
using BetterCms.Core;
using BetterCms.Core.Environment.Host;
using TestingCms.App_Start;
namespace TestingCms
{
public class MvcApplication : System.Web.HttpApplication
{
private static ICmsHost cmsHost;
protected void Application_Start()
{
cmsHost = CmsContext.RegisterHost();
/* DO NOT FORGET TO REMOVE DEFAULT ROUTE REGISTRATION!
FOLLOWING SOURCE CODE SHOULD BE REMOVED:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
*/
// [YOUR CODE]
cmsHost.OnApplicationStart(this);
}
protected void Application_BeginRequest()
{
// [YOUR CODE]
cmsHost.OnBeginRequest(this);
}
protected void Application_EndRequest()
{
// [YOUR CODE]
cmsHost.OnEndRequest(this);
}
protected void Application_Error()
{
// [YOUR CODE]
cmsHost.OnApplicationError(this);
}
protected void Application_End()
{
// [YOUR CODE]
cmsHost.OnApplicationEnd(this);
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
// [YOUR CODE]
// Uncomment following source code for a quick Better CMS test if you don't have implemented users authentication.
// Do not use this code for production!
var roles = new[] { "BcmsEditContent", "BcmsPublishContent", "BcmsDeleteContent", "BcmsAdministration" };
var principal = new GenericPrincipal(new GenericIdentity("TestUser"), roles);
HttpContext.Current.User = principal;
cmsHost.OnAuthenticateRequest(this);
}
}
}

Related

How to find out which method an API call is hitting in my MVC application?

I inherited an MVC application and I can normally deduce where an API call hits but this time I'm stumped. API call info:
Request URL: http://localhost:3100/api/account
Request Method: GET
Status Code: 200 OK
RouteConfig looks like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Global.asax has:
private const string _WebApiPrefix = "api";
private static string _WebApiExecutionPath = String.Format("~/{0}", _WebApiPrefix);
private static bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(_WebApiExecutionPath);
}
And I'm not really sure where else to look. There is no AccountController that I can find. Is there some way that I can find the controller entry point into the application for this call?
Create an action filter to all controllers.
public class LogFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
Debug.WriteLine(string.Format("Action {0} on Controller {1}", actionContext.ActionDescriptor.ActionName, actionContext.ControllerContext.ControllerDescriptor.ControllerName));
}
}
on global.asax.cs
protected void Application_Start()
{
GlobalConfiguration.Configuration.Filters.Add(new LogFilter());
}
Just check the console after typing "http://localhost:3100/api/account". It will log the action and the controller. Or place a breakpoint in OnActionExecuting method, the next method executed will be he method that you are searching for.

I get a 404 not found when I navigate to my route

Hello I have a Controller called help in my project like this:
public class HelpController : Controller
{
// GET: Help
public string Index()
{
return "test help";
}
}
This is my route.config file
using System.Web.Mvc;
using System.Web.Routing;
namespace ProductsApp.App_Start
{
public class RouteConfig
{
public static void RegisterRoutes (RouteCollection routes)
{
RouteTable.Routes.RouteExistingFiles = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
My Global.asax
using ProductsApp.App_Start;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
namespace ProductsApp
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
}
When I navigate to the /Help/Index, I get a 404 server error. If I navigate to /Help. My app instantiates the Home controller. What could be wrong?
Do you have Areas > HelpPage inside your web? Maybe this is beign called instead of your controller.
You can implement attribute routing, with them, you can specify what is the route of that controller and method, instead of the RouteConfig.
In my opinion, this approach keeps the code more maintanable and easy to understand. And you can even, use it to make versions of your controllers.
this is an exemple of how you can achieve Attribute routing:
[RoutePrefix("api/v2/network/account")]
public class AccountController : ApiController
{
[Route("{login}"), HttpGet]
public Account GetAccountByLogin(string login)
{
// Code Logic Here
}
}
And how you call this method? you will not type yourapi/api/Account/GetAccountByLogin/userlogin because your api or mvc won't recognize that url, instead, it will recognize it when you type: yourapi/api/v2/network/Account/userlogin.
These inks can help you:
For areas:
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/areas
For Attribute Routing:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Web API 2 routing fails for literal segment

I'm facing an issue with Web API 2 routing for literal segments.
In one project, I have ASP.NET MVC and WebAPI2 running together, the project is also running MVC areas.
Under each area, there is API folder which contains APIs. I'm facing an issue when trying to request the following url:
{host}/accesscontrol/api/reporting/bookings.
accesscontrol here is the area name
reporting is the controller
bookings is a literal segment.
The error I'm getting:
No action was found on the controller 'Reporting' that matches the request.
This is the controller that should receive this request:
[RoutePrefix("accesscontrol/api/reporting")]
public class ReportingController : ApiController
{
[Route("bookings")]
[ResponseType(typeof(Booking))]
[HttpGet]
public async Task<IHttpActionResult> Bookings(string q = null)
{
//Code to get data
return Ok(bookings);
}
}
When I remove [Route('Bookings')] attribute, the request is working well regardless if Bookings segment is there or not.
This is the configuration of routing under area registration class:
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapHttpRoute(
"AccessControlApi_default",
"accesscontrol/api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
context.MapRoute(
"AccessControl_default",
"accesscontrol/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
How can I let the app to understand those literal segments under areas?
Edit
I'm calling RegisterAllAreas in Global.asax.cs file, as follow:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
I managed to make it work just add action after your controller in your MapHttpRoute and change [Route("bookings")] attribute to [ActionName("bookings")] and everything works.
context.Routes.MapMvcAttributeRoutes();
context.Routes.MapHttpRoute(
"AccessControlApi_default",
"Accesscontrol/api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional});
I hope this will help you out.
I resolved my issue by moving: AreaRegistration.RegisterAllAreas(); from global.asax.cs file to RouteConfig.cs file.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
AreaRegistration.RegisterAllAreas();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] {"WebPortal.Controllers"}
);
}
}

ASP.NET MVC routing parameters not working with areas

I'm currently playing around with areas and routing within them. What I'm trying to achieve is to be able to have a URL that looks like this;
PracticeAdmin/Practice/[Practice Name]
which I would then be able to add things like Edit and Delete to the end of.
I have achieved this in the past when not working with areas by adding this annotation to the action
[Route("PracticeAdmin/Practices/{practiceName}")]
public ActionResult Details(string practiceName)
this would produce the URLs that I would like. The problem I am having is that when I am trying to do this when using areas I get links that look like this;
PracticeAdmin/Practices?practiceName=Practice1
which is not what I am looking for.
The code that I am using to try and produce this with is
PracticeAdminAreaRegistration.cs
using System.Web.Mvc;
namespace TrainingPortal.Areas.PracticeAdmin
{
public class PracticeAdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "PracticeAdmin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"PracticeAdmin_default",
"PracticeAdmin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "TrainingPortal.Areas.PracticeAdmin.Controllers" }
);
}
}
}
RouteConfig.cs
namespace TrainingPortal
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "TrainingPortal.Controllers" }
);
}
}
}
I have called MapMvcAttributeRoutes here which I believe should mean that the routes are registered even within areas. I have also tried putting the necessary code within PracticeAdminAreaRegistration to do the same thing with no effect.
PracticeAdminController.cs
namespace TrainingPortal.Areas.PracticeAdmin.Controllers
{
public partial class PracticesController : Controller
{
private TpContext db = new TpContext();
// GET: PracticeAdmin/Practices
public virtual ActionResult Index()
{
return View(db.Practices.ToList());
}
[Route("PracticeAdmin/Practice/{practiceName}")]
public virtual ActionResult Details(string practiceName)
{
if (string.IsNullOrWhiteSpace(practiceName))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Practice practice = db.Practices.FirstOrDefault(m => m.PracticeName.ToLower() == practiceName);
if (practice == null)
{
return HttpNotFound();
}
return View(practice);
}
...
Obviously it carries on with other methods but they all follow the same approach as this one.
Index.cshtml snippet
#Html.ActionLink("Delete", MVC.PracticeAdmin.Practices.Delete(item.PracticeName))
#Html.ActionLink("Delete2", "Delete", new { practiceName = item.PracticeName })
Within PracticeAdminArea/Views/Practices/Index.cshtml I have tried using both T4MVC and the normal ActionLink approach which generate exactly the same link (unsurprisingly).
Summary
I have no idea why the Routes I have specified don't appear when trying to create an ActionLink in an area, so I was wondering whether anyone is able to point me in the direction of how I would be able to fix this and get the URL to look how I would like it to?
After a bit of playing around I managed to get it working. The way that I ended up fixing it was by calling AreaRegistration.RegisterAllAreas() from the RouteConfig.RegisterRoutes() after having called MapMvcAttributeRoutes()
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
AreaRegistration.RegisterAllAreas();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "TrainingPortal.Controllers" }
);
}
}
As you're not allowed to call this method twice (or ASP.NET gets rather upset with you having registered the same route names twice) I removed the call to AreaRegistration.RegisterAllAreas() from Global.asax leaving it looking like this;
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Unfortunately this alone didn't solve the problem, I also had to make a couple modifications to the Controller as well. The modifications were to add the RoutePrefix and RouteArea attributes to the Controller like this;
[RouteArea("PracticeAdmin")]
[RoutePrefix("Practice")]
public partial class PracticesController : Controller
{
This had the added benefit that when specifying the route for a particular action through the Route attribute you didn't have to specify those parts any more, so originally an action's signature would have looked like this;
// GET: PracticeAdmin/Practices/{practiceName}/Members
[Route("PracticeAdmin/Practices/{practiceName}/Members")]
public virtual ActionResult Members(string practiceName)
{
it would now look like this;
// GET: PracticeAdmin/Practices/{practiceName}/Members
[Route("{practiceName}/Members")]
public virtual ActionResult Members(string practiceName)
{
After making all those changes, the website is behaving as expected.

Determining which controller and action is handling a particular URL in ASP.NET MVC

Given a particular URL, how do I find out for sure which controller action it is being routed to (perhaps in the context of a large application with many controllers and a complex route registry)?
I'm not asking how to configure routes.
Something like this for controller:
string controller = RouteData.GetRequiredString("controller");
And for action:
string action = RouteData.GetRequiredString("action");
For example you can use it in your base controller class:
public class YouControllerBase: Controller
{
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
string controller = requestContext.RouteData.GetRequiredString("controller");
string action = requestContext.RouteData.GetRequiredString("action");
}
}
Or use it in global.asax:
protected void Application_BeginRequest(object sender, EventArgs e)
{
RouteData routeData = RouteTable.Routes.GetRouteData(
new HttpContextWrapper(HttpContext.Current));
var action = routeData.GetRequiredString("action");
}
You could try this ASP.NET Routing Debugger:
(source: haacked.com)
pete,
in code, you can use an actionfilter to determine whats going on:
public class AddUrlInfoToSessionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
// where we are now - do something with the vars in real app
var currentActionName = filterContext.ActionDescriptor.ActionName;
var currentControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var currentRouteData = filterContext.RouteData;
var currentUrlInfo = new UrlHelper(filterContext.RequestContext);
string url = RouteTable.Routes.GetVirtualPath(filterContext.RequestContext, currentRouteData.Values).VirtualPath;
}
}
}
and then decorate each controller that your interested in as below (or put it onto a basecontroller):
[HandleError]
[AddUrlInfoToSessionAttribute]
public class HomeController : Controller
{
// controller stuff
}
[AddUrlInfoToSession]
public abstract class BaseController : Controller
{
}
hope this helps
jim
EDIT: just tidied the example up a bit by adding the following to the filter method:
string url = RouteTable.Routes.GetVirtualPath(filterContext.RequestContext, currentRouteData.Values).VirtualPath;
Two simple steps:
Add 2 reference in your project: MvcFakes.dll,RouteDebugger.dll
Entering the following URL: /RouteDebugger
The 2 dlls are contained here
Chapter09Code.zip\Code\CS\MvcApplication1\MvcApplication1\bin
It depends on Routes that are registered to resolve the URL
The default conventions is as follows :
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
Index action will be called on HomeController.
The Controller and Action that are used are determined by the registered routes. Look in your Global.ascx.cs
Here is the default route mapping that comes as standard with a new MVC app. So if your url is http://yourdomain/SomeSiteSection/SomeThing/ then MVC will look for a controller called SomeSiteSectionController and an Action called SomeThing.
public class MvcApplication : System.Web.HttpApplication
{
//...
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}

Resources