Orchard: Custom Registration fields - asp.net

For my Orchard project, I need some additional information from the user at registration time. (Say, First Name, Last Name, Pants Color). This information must be entered while registering and can not be deferred until later (as per client's orders).
I tried using the Profile and Extended Registration plugins to ask for those, but as far as I see, this only gives me optional fields to display in the registration form. Is there a way to present fields that are mandatory?
I also had a quick foray into overwriting the AccountController's Register method, as per this discussion, but I couldn't get it to work: The controller is in a different place, it can't be subclassed and even if I force it to, code is never executed. I presume they are using a much older version of Orchard.
So, in which direction should I go to create a mandatory field that is close to the Orchard philosophy? Should I create a new field type that rejects empty values maybe? (is that even possible)?

I wrote the ExtendedRegistration module because of that same need.
You need to create a custom part, e.g.: MyRegistrationPart.
Then you add that part to the User ContentType.
In your part just add the [Required] attribute (Data annotations) to any properties that are mandatory.
Registration will not succeed until those mandatory values have been filled out!
Hope it's clear now.

While this probably won't answer your question just wanted to point out that it is my understanding that you don't need to override/subclass the AccountController class. Instead you need to "overwrite" the Users/Account/Register route by adding your own with a higher priority. To do that you need to implement an IRouteProvider as part of our module. Since it's an IDependency it will be loaded and processed automagically at run time. Something like:
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
routes.AddRange(GetRoutes());
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
// Make sure to be higher than the default
Priority = ##### PRIORITY HERE (int) ######,
Route = new Route(
"Users/Account/Register",
new RouteValueDictionary {
{"area", "#### YOUR MODULE AREA HERE ####"},
{"controller", "#### YOUR ACCOUNT CONTROLLER HERE ####"},
{"action", "#### YOUR REGISTER ACTION HERE ####"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "#### YOUR MODULE AREA HERE ####"}
},
new MvcRouteHandler())
}
};
}
}

Related

Umbraco and dynamic URL content at root level

I need to port a website to asp.net and decided to use Umbraco as the underlying CMS.
The issue I'm having is I need to retain the URL structure of the current site.
The current URL template looks like the following
domain.com/{brand}/{product}
This is hard to make a route for since it mixes in with all the other content on the site. Like domain.com/foo/bar which is not a brand or product.
I've coded up a IContentFinder, and injected it into the Umbraco pipeline, that check the URL structure and determins if domain.com/{brand} matches any of the known brands on the site, in which case i find the content by its internal route domain.com/products/ and pass along {brand}/{model} as HttpContext Items and return it using the IContentFinder.
This works, but it also means no MVC controller is called. So now I'm left with fetching from the database in the cshtml file which is not so pretty and kind of breaks MVC conventions.
What i really wan't is to take the url domain.com/{brand}/{product} and rewrite it to domain.com/products/{brand}/{product} and then being able to hit a ProductsController serving up the content based on the parameters brand and product.
There are a couple of ways to do this.
It depends a bit on your content setup. If your products exist as pages in Umbraco, then I think you are on the right path.
In your content finder, remember to set the page you've found on the request like this request.PublishedContent = content;
Then you can take advantage of Route Hijacking to add a ProductController that will get called for that request: https://our.umbraco.org/Documentation/Reference/Routing/custom-controllers
Example implementation:
protected bool TryFindContent(PublishedContentRequest docReq, string docType)
{
var segments = docReq.Uri.GetAbsolutePathDecoded().Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
string[] exceptLast = segments.Take(segments.Length - 1).ToArray();
string toMatch = string.Format("/{0}", string.Join("/", exceptLast));
var found = docReq.RoutingContext.UmbracoContext.ContentCache.GetByRoute(toMatch);
if (found != null && found.DocumentTypeAlias == docType)
{
docReq.PublishedContent = found;
return true;
}
return false;
}
public class ProductContentFinder : DoctypeContentFinderBase
{
public override bool TryFindContent(PublishedContentRequest contentRequest)
{
// The "productPage" here is the alias of your documenttype
return TryFindContent(contentRequest, "productPage");
}
}
public class ProductPageController : RenderMvcController {}
In the example the document type has an alias of "productPage". That means that the controller needs to be named exactly "ProductPageController" and inherit the RenderMvcController.
Notice that it does not matter what the actual pages name is.

ASP.NET MVC How does AuthorizeAttribute support checking Roles?

In my controllers, I have code like [Authorize(Roles = "Administrators")] annotated above some actions, and I want to know how AuthorizeAttribute uses the Roles parameter (the implementation of the checking mechanism). My goal is to create an extension of this class, called PrivilegeAttribute for example, so that I can annotate actions like [Privilege(Privileges = "read")]. In this class, I would check if the Role of the user has at least one of the privileges in this custom filter (read in this example). I have already created the association between roles and privileges in the code and in the database, and what I want help with is checking whether the role is associated to the privilege.
I tried seeing if that information is there in HttpContextBase.User.Identity but I couldn't find it.
Thank you.
If you don't need your own custom attribute and could live with using someone else attribute, than I would suggest to use the package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc as described here
Blog Post by Dominick Baier
and here
Git Hub Sample Code for the Package
so it basically works like this:
you put an attribute over your action like this:
[ResourceAuthorize("View", "Customer")]
The first argument is the name of the Action to check, the second one is the name of the attribute.
Then you derive from ResourceAuthorizationManager in your code and override the CheckAccessAssync Method
public class MyAuthorization : ResourceAuthorizationManager
{
public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
// getting the roles that are connected to that resource and action
// from the db. Context could of course be injected into the
// constructor of the class. In my code I assume that the table
// thank links roles, resources and actions is called Roles ToActions
using(var db = MyContext())
var roles = db.RolesToActions // Use your table name here
.Where(r => r.Resource == resource && r.Action == action).ToList();
foreach(var role in roles)
{
if(context.Principal.IsInRole(role.Name)
{
return Ok();
}
}
return Nok();
}
}
}
So I hope this helps. If you prefer to implement your own attribute however, than the source code from the ResourceAuthorization GitHub Repository should be a good starting point

Orchard CMS - determining if Model is valid in Content Item Driver

In my instance of Orchard, I have a custom content type which has a custom content part. In the "editor driver" for the content part, I need to check to see if the container content item is valid (i.e. passes validation).
The normal ModelState won't work here because of how Orchard works - and I can determine if the content part is valid, but I need to know about the entire content item (there are other content parts within the content item).
I know there are ways to execute code once a content part is published / created using lifecycle events (http://docs.orchardproject.net/Documentation/Understanding-content-handlers), but there's no way (that I know of) to pass those events information.
Basically, I need to execute a method if the content item is valid, and I need to pass the method information contained within the ViewModel.
There may be (and probably is) a better way to do this, but I'm struggling to find a way within Orchards framework.
sample code:
//POST
protected override DriverResult Editor(EventPart part, IUpdateModel updater, dynamic shapeHelper)
{
var viewModal = new EventEditViewModel();
if (updater.TryUpdateModel(viewModal, Prefix, null, null))
{
part.Setting = viewModal.Setting;
}
//here's where I need to check if the CONTENT ITEM is valid or not, for example
if (*valid*)
{
DoSomething(viewModal.OtherSetting);
}
return Editor(part, shapeHelper);
}
Note: I am using Orchard version 1.6.
No easy way to do that from inside a driver, I'm afraid. Too early. You can access other parts by doing part.As<OtherPart>, but those may or may not be updated yet at this point.
You may try utilizing handlers and OnPublishing/OnPublished (and other) events like this:
OnPublishing<MyPart>((ctx, part) =>
{
// Do some validation checks on other parts
if (part.As<SomeOtherPart>().SomeSetting == true)
{
notifier.Error(T("SomeSetting cannot be true."));
transactions.Cancel();
}
});
where transactions is ITransactionManager instance, injected in ctor.
If you need more control, writing your own controller for handling item updates/creates is the best way to go.
In order to do that (assuming you already have your controller in place), you need to use handler OnGetContentItemMetadata method to point Orchard to use your controller instead of the default one, like this:
OnGetContentItemMetadata<MyPart>((context, part) =>
{
// Edit item action
context.Metadata.EditorRouteValues = new RouteValueDictionary {
{"Area", "My.Module"},
{"Controller", "Item"},
{"Action", "Edit"},
{"id", context.ContentItem.Id}};
// Create new item action
context.Metadata.CreateRouteValues = new RouteValueDictionary {
{"Area", "My.Module"},
{"Controller", "Item"},
{"Action", "Create"});
});

MVC3 how to minimize the number of controllers

i am new to MVC3 and our project needs something like:
http://www.abc.com/product_1/product_1_subpage/...
http://www.abc.com/product_2/product_2_subpage/...
right now, i have product_1 as a controller; product_1_subpage as an action of this controller, however, think about i have over 100 different products, i cannot keep create over 100 controllers for each single product, i need to do something on this structure, any idea?
thank you very much for your help, really appreciate any input.
You would probably want to have only a single Controller called Products, for all your products, instead of having to add a new controller for every product.
With custom routes, or the default routing for that matter, you would still be able to generate individual links for individual products. Also, if you were to use your approach with a new controller for every product (which you really shouldn't!), you would have to re-compile and deploy your application every time you want to add another product - which would be a pain to maintain.
It sounds like you should have a look at the tutorials about MVC provided by the .Net team to get some basic understand of MVC, and how to think about it.
Use custom routes:
routes.MapRoute(
"ProductsRoute", // Route name
"products/{productName}/{subName}/{id}", // URL with parameters
new { controller = "Product", action = "View", id = UrlParameter.Optional } // Parameter defaults
);
That would make the following work:
public class ProductController : Controller
{
// http://yourweb/products/goggles/xray/Elite2000
public ActionResult View(string productName, string subName, string id)
{
}
}
how about changing the format of the url a little to take advantage of the routing:
http://www.abc.com/product/subpage/1

Unity 2 trouble referencing RegisterInstance using InjectonProperty

I have the following code:
Unity Container:
Settings settings = CreateSettings();
container.RegisterInstance(settings)
.RegisterType<MyHttpHandler>(new InjectionProperty[]
{
// How do I tell Unity to inject my settings created above?
new InjectionProperty("Settings", new ResolvedParameter(????))
});
MyHttpHandler:
public class MyHttpHandler: IHttpHandler
{
public MyHttpHandler()
{
IoC.Inject(this);
}
public Settings Settings
{
get;
set;
}
}
How do I tell Unity to inject the settings? This works just fine with interfaces but not sure how to proceed here.
Any help is appreciated.
It just goes off the type. You've registered an instance for the Settings class, so you just need to tell it to inject that type:
container.RegisterInstance(settings)
.RegisterType<MyHttpHandler>(
new InjectionProperty("Settings", new ResolvedParameter<Settings>());
(Note that you don't need the extra array, RegisterType takes a variable parameter list.)
Since this is a common requirement, there are shorthands you can use. First off, if you're resolving a dependency and you just need the default (non-named) registration, you don't need to use ResovledParameter, you can just pass the type object:
container.RegisterType(settings)
.RegisterType<MyHttpHandler>(
new InjectionProperty("Settings", typeof(Settings));
But, we can also go simpler than that. If you're using the default for a property based on the type, you don't need to pass the value at all - the container will simply use the type of the property. So you can just say:
container.RegisterType(settings)
.RegisterType<MyHttpHandler>(
new InjectionProperty("Settings"));
and the container will figure it out.

Resources