Hook up Auth0AccountController in Umbraco 7 - authentication

Has anyone successfully integrated Auth0 with Umbraco 7 for member (front-end public users, not CMS back-end users) authentication?
I've successfully integrated with owin startup and dealing with signin-auth0 response. However I'm stuck on hooking up the Auth0AccountController to work with Umbraco (I'm getting a 404). Any suggestions?
I've tried adding ~/Auth0Account to the "umbracoReservedPaths" appSetting, but I just get a slightly different looking 404 (not controlled by Umbraco by looks of it).
I've also tried mapping the route in Startup.cs using
RouteTable.Routes.MapRoute(
"Auth0Account",
"Auth0Account/{action}",
new
{
controller = "Auth0Account"
}
);
but that results in a "No route in the route table matches the supplied values" error.
Any ideas?

Mapping the Auth0Account route in Startup.cs was correct:
RouteTable.Routes.MapRoute(
"Auth0Account",
"Auth0Account/{action}",
new
{
controller = "Auth0Account"
}
);
Turns out my problem was with the default redirect RedirectToLocal method in the Auth0AccountController controller. It was doing a
return RedirectToAction("Index", "Home");
which I didn't have a controller hooked up for. I replaced this with an Umbraco compatible redirect instead.
Also, instead of Auth0AccountController inheriting from Controller it might be useful to inherit from Umbraco.Web.Mvc.SurfaceController or Umbraco.Web.Mvc.RenderMvcController to expose useful Umbraco methods to the code.

Related

.net core 500 internal server error after adding new api controller

I have created a .net core application which currently has one api controller and everything works fine. The problem is when I add another api controller to the solution with a different name and route. If I try to to run the APIs I get 500 internal server error once I add another controller.
If I remove the newly added api controller everything works fine again.
Any help would be appreciated!
Seems like the problem is with the name (Name = "Get") attribute added to HttpGet method was the problem. All the controllers had the same Name attribute and hence the error. Removing the Name attribute from controllers solved the problem.
[HttpGet("{id}", Name = "Get")]
public string Get(int id)
{
return "value";
}

Understanding ASP.net mvc4 code

public ActionResult Index()
{
return RedirectToAction("Index", "Login");
}
What does this code do? Index and login are views here?
This tells MVC to redirect to specified action instead of rendering HTML. In this case, browser receives the redirect notification and make a new request for the specified action. This acts like as Response.Redirect() in Asp.Net WebForm.
Moreover, RedirectToAction construct a redirect url to a specific action/controller in your application and use the route table to generate the correct URL.
For more about this look https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.118).aspx

Can Umbraco pass a model to view

I am quite new to this Umbraco MVC.
I need to pass some data bound to a model to my partial view from the GET action method.
This simply is not working in a regular MVC way.
[httpget]
public ActionResult Membership()
{
SupplierMembershipInfoModel mm = new SupplierMembershipInfoModel();
mm.ProductPackage = "sssssssss";
ViewBag.status = Request.QueryString["status"];
return PartialView("MembershipPartial", mm);
}
my view:
#model Umbraco.Web.Models.SupplierMembershipInfoModel
some html.....
<td>#Model.ProductPackage</td>
I don't get data here...and the debug never hits the action. But it hits any POST action method.
I know i am doing something wrong...but just don't know what the mistake is??
Any ideas??
As #Sebastiaan points out, the best place to start is the Umbraco community site. There is documentation specific to your issue here: http://our.umbraco.org/documentation/Reference/Templating/Mvc/child-actions
In a nutshell, you want to display a child action on your page and Umbraco uses SurfaceControllers for this. A SurfaceController is simply a Controller that inherits from Umbraco.Web.Mvc.SurfaceController. This provides you Controller with access to the Umbraco context - see here (http://our.umbraco.org/documentation/Reference/Templating/Mvc/surface-controllers).
Either way, you should read the whole documentation section on templating as it will give you a lot of insight into how Umbraco MVC is managed.

injecting changing view engine list

I'm trying to develop a multi-tenancy project wherein each client can have their own specific view engines.
Specifically I'd like to compile the views to a DLL (using RazorEngine) and have an individual RazorViewEngine for each client but also provide a fallback to the standard RazorViewEngine if no matching views are found, just as the MVC framework does if you have multiple view engines specified.
I have found I can inject view engines using autofac in the Global.asax of my MVC 4 project using:
ViewEngines.Engines.Clear();
var builder = new ContainerBuilder();
builder.RegisterType<WebFormViewEngine>().As<IViewEngine>();
Now I also want to provide tenant specific overrides as mentioned above which I can do with the following code:
var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
mtc.ConfigureTenant("Client1", b => b.RegisterType<RazorViewEngine>().As<IViewEngine>());
DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));
In this example code I just wanted to see if I could set the WebFormsViewEngine as a fallback and then enable the RazorViewEngine for a specific tenant.
Upon loading and browsing to a non-tenant url, mvc will resolve just the WebFormsViewEngine as expected (through calling the DependencyResolver and in turn Autofac), this works as expected however when I then visit a url that would also include the RazorViewEngine no views are found, even though a valid razor view exists.
Conversely if I stop IISExpress or do something to generate an app pool recycle and visit a tenantable url first both view engines are registered.
From what I can tell MVC caches the list of view engines retrieved after the first call to the MultiServiceResolver.
internal IViewEngine[] CombinedItems
{
get
{
IViewEngine[] combinedItems = _combinedItems;
if (combinedItems == null)
{
combinedItems = MultiServiceResolver.GetCombined<IViewEngine>(Items, _dependencyResolver);
_combinedItems = combinedItems;
}
return combinedItems;
}
}
Is there a way to override this caching or another better way to achieve what I'm trying to get here?

How do I set push-state in durandaljs 2.0 the works on refresh?

I'm using durandaljs 2.0. I've installed the durandal starter-kit as suggested and explained here. In the shell I'm returning router.activate({ pushState: true } ); as explained in the relevant documentation (see the bottom of the page).
Happily, the URL is indeed in a 'push state' format, e.g. http://localhost:61285/flickr - the problem is that when I refresh the page I get a 404 error telling me "the resource cannot be found". If I set push-state to false ({pushState: false} above) I get a hashed URL, e.g. http://localhost:61285/#flickr - and now a refresh does work. So, how do I set up a push state mode in durandaljs 2.0 that will work with refresh?
Thanks,
Elior
Maybe to late...but
just change the routes config.
simple as this :
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" }
);
When you refresh the page, the browser will make a request to the server with that URL http://localhost:61285/flickr.
What's probably happening is that if you are using ASP.NET MVC, the server is trying to locate a Controller called flickr and it throws an exception because obviously there isn't any resource with that name.
In order to get rid of this exception you should configure the server to serve the same HTML of the APP but for unknown URL's. This can be achieved using IIS URL Rewrite in ASP.NET.
So after setting up properly the server, by requesting an unknown URL it would return the initial view for the app plus whatever you pass in the query string parameters so the router can do its job at client side.
In this blog post you will find more information about how to configure ASP.NET to handle this scenarios. In the article the author uses AngularJS, however it will be the same for Durandal.
RainerAtSpirit and margabit, you're both right, thank you. Here is how I implemented the server side:
First I should note that all the interaction with the server is done via WebApi controllers.
so, for example, if the URL is:
http://localhost:61285/home/category2/subCategory22 (for a localhost), the server tries to look for a controller called 'home' and an action in it called 'category2'. Since there's no such action, I get a 404 error.
What I wanted is that the server WILL call the 'home' controller, but send the rest of the URL as parameters to the client. My solution was to add a hash after the controller's name, so that the URL will look like this: http://localhost:61285/home/#/category2/subCategory22. If this would happen then the client will take care of the hashed part with no 404 error.
For this to happen:
I added the following to 'web.config':
<customErrors mode="On" defaultRedirect="Error">
<error statusCode="404" redirect="Error" />
</customErrors>
Then I create a controller named 'ErrorController' with the following class in it:
public class ErrorController : ApiController
{
[HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH"), AllowAnonymous]
public HttpResponseMessage Handle404()
{
string [] parts = Request.RequestUri.OriginalString.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
string parameters = parts[ 1 ].Replace("aspxerrorpath=","");
var response = Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Location = new Uri(parts[0].Replace("Error","") + string.Format("#{0}", parameters));
return response;
}
}
what happens is that when the server get a URL with no relevant action as I mentioned above, it redirects it to this controller in the following format: http://localhost:61285/Error?aspxerrorpath=home/category2/subCategory22
as you can see, I manipulate this to add the hash and remove the unnecessary info: http://localhost:61285/home/#/category2/subCategory22 and the redirect the server to the 'home' controller.
You might wonder why I do all of this - the reason is that Durandal, a wonderful platform, enables me to use push state, but in order for that to happen I have to work-around the server getting a non-hashed URL and pass it to the client despite the fact there's no relevant controller/action; Durandal get's a hashed URL but removes the hash automatically and the user eventually sees a hash-less URL while Durandal provides all the necessary push state functionality.
Elior