香港鬼片四个人打麻将:Integrating N2CMS into Who Can Help Me? Part 3
来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 22:25:09
Integrating N2CMS into Who Can Help Me? Part 3
Tags: N2 CMS, Who Can Help Me February 12th, 2010This is part 3 in my series of posts about integrating the .Net open source content management system N2CMS into the Sharp Architecture demo application Who Can Help Me?.
In the first and second post I
- Added the N2 assemblies
- Added the edit site to the web project
- Created the initial content definitions
- Created the database schema
- Added root nodes to the CMS database
- Updated the Web.config
- Set up the N2 Content Routes and intialised the CMS engine
Step 8 – Add a base CMS controller
To link our content items in the CMS database to the appropriate controllers, we need our CMS related controllers to inherit from the N2 controller class ContentController
We already have a BaseController class in WCHM, as we wanted to set up some defaults for the master page name to use etc in the Spark views. Ideally, I’d like to be able to reuse this code, but as our CMS controllers need to be generic, I had to create a new base class, N2Controller
01.
namespace
WhoCanHelpMe.Web.Controllers
02.
{
03.
using
System.Web.Mvc;
04.
using
N2;
05.
using
N2.Web.Mvc;
06.
07.
///
08.
/// Base N2 controller
09.
///
10.
///
11.
/// The content item type
12.
///
13.
public
class
N2Controller : ContentController where T : ContentItem
14.
{
15.
///
16.
/// Stores the site master name
17.
///
18.
private
const
string
MasterName =
"Site"
;
19.
20.
///
21.
/// Default controller action
22.
///
23.
///
24.
/// The default view with the current CMS item as the model
25.
///
26.
public
override
ActionResult Index()
27.
{
28.
return
View(CurrentItem);
29.
}
30.
31.
///
32.
/// Returns a view result with default view and master name
33.
///
34.
///
35.
/// View Result
36.
///
37.
protected
new
ViewResultBase View()
38.
{
39.
return
View(
string
.Empty, MasterName,
null
);
40.
}
41.
42.
///
43.
/// Returns a view result with specified view name and the default master name
44.
///
45.
///
46.
/// The view name.
47.
///
48.
///
49.
/// View Result
50.
///
51.
protected
new
ViewResultBase View(
string
viewName)
52.
{
53.
return
View(viewName, MasterName,
null
);
54.
}
55.
56.
///
57.
/// Returns a view result with the specified view name, default master name
58.
/// and the specified model
59.
///
60.
///
61.
/// The view name.
62.
///
63.
///
64.
/// The model.
65.
///
66.
///
67.
/// View Result
68.
///
69.
protected
new
ViewResult View(
string
viewName,
object
model)
70.
{
71.
return
View(viewName, MasterName, model);
72.
}
73.
74.
///
75.
/// Returns a view result with default view and master name
76.
///
77.
///
78.
/// The model.
79.
///
80.
///
81.
/// View Result
82.
///
83.
protected
new
ViewResult View(
object
model)
84.
{
85.
return
View(
string
.Empty, MasterName, model);
86.
}
87.
}
88.
}
Changeset reference 55248
I also added my specs for the behaviour of the base CMS controller:
view sourceprint?01.
namespace
MSpecTests.WhoCanHelpMe.Web.Controllers
02.
{
03.
using
System.Web.Mvc;
04.
using
System.Web.Routing;
05.
using
global::WhoCanHelpMe.Domain.Cms.Pages;
06.
using
global::WhoCanHelpMe.Web.Controllers;
07.
using
Machine.Specifications;
08.
using
Machine.Specifications.AutoMocking.Rhino;
09.
using
Machine.Specifications.Mvc;
10.
11.
public
abstract
class
context_for_n2_controller : Specification>
12.
{
13.
Establish context = () =>
14.
{
15.
var routeData =
new
RouteData();
16.
routeData.Values.Add(
"n2_item"
,
new
HomePage { Name =
"Home Page"
});
17.
18.
subject.ControllerContext =
new
ControllerContext() { RouteData = routeData };
19.
};
20.
}
21.
22.
[Subject(
typeof
(N2Controller<>))]
23.
public
class
when_the_n2_controller_is_asked_for_the_default_action : context_for_n2_controller
24.
{
25.
static
ActionResult result;
26.
27.
Because of = () => result = subject.Index();
28.
29.
It should_return_the_default_view = () =>
30.
result.ShouldBeAView().And().ShouldUseDefaultView();
31.
32.
It should_use_the_default_master_page = () =>
33.
result.ShouldBeAView().And().MasterName.ShouldEqual(
"Site"
);
34.
35.
It should_populate_the_view_model_with_the_current_item_from_the_cms = () =>
36.
result.Model().Name.ShouldEqual(
"Home Page"
);
37.
}
38.
}
What I’ve done here is add a base Index() action to the CMS controller that will just pass the current content item as the model into the view. In reality, I’ll probably not use this as in WCHM we’re pretty strict on using viewmodels to bind to our views, rather than domain entities (which is what the CMS definitions really are) however, this allows a quick and dirty way to pass the CMS content into the view as your’re building up your application. With anything but the most simple application, your view will be made up of more than just the content from the CMS, so you’ll need to build up a more specific model for the view anyway.
Note how N2 works – when it realises that it can handle an incoming request for a URL with a content item it creates that item for us and puts it into the RouteData before calling the associated controller. This means that we easily have access to the current item via the ContentController
Changeset reference 55314
Step 9 – Update the HomeController
The goal of this exercise was to surface content from N2CMS onto our WCHM Home page and About page. We’ve now got a base CMS controller that we can use, so next I refactor the existing HomeController to inherit N2Controller.
view sourceprint?1.
[Controls(
typeof
(HomePage))]
2.
public
class
HomeController : N2Controller
3.
{
4.
...existing code the same
for
now...
5.
}
The things to note are that we now inherit N2Controller which means we can easily access the current item (as a HomePage) from within our controller, and the Controls[] attribute, which tells N2 which content types this controller is going to handle. Any requests matching a content item of type HomePage will now come this way.
We also need to update our specs as because we now inherit N2Controller, which in turn inherits ContentController
01.
Establish context = () =>
02.
{
03.
var routeData =
new
RouteData();
04.
home_page =
new
HomePage();
05.
routeData.Values.Add(
"n2_item"
, home_page);
06.
07.
home_view_model_mapper = DependencyOf();
08.
news_tasks = DependencyOf();
09.
10.
ServiceLocatorHelper.AddCachingService();
11.
12.
subject.ControllerContext =
new
ControllerContext() { RouteData = routeData };
13.
};
Changeset reference 55315
At this point, our site should build, compile, pass tests and load up in the normal WCHM fashion, so lets take a pause and go off tangent ever so slightly…
Step 10 - Authentication
This is a bit of a tricky one in WCHM as we’re already using Open ID for users to authenticate themselves in order to create profiles. N2 uses the Asp.Net membership providers to manage users and access to the CMS system (although it has it’s own custom provider that stores the users as content items in it’s own database). We don’t want to allow anyone to be able to get into the CMS, but we need to be able to distinguish between those that can and cannot with one unified mechanism.
I went round in circles a bit with this one, and with some help from Jon, I ended up back right where I started, which was to do nothing. The solution I came up with is a little hacky, but it works, and requires no changes to N2, or the WCHM authentication, so all is good for now.
In order to set up a CMS user, I first created a profile in the usual way in WCHM, using my preferred Open ID provider. I then opened the Profiles database table in the WCHM database and found the Open ID username that has been returned and stored against my profile. If, like me, you use a Google account, it will look something like this: (this is not my real Open ID!)
https://www.google.com/accounts/o8/id?id=asdasdasdasd6auasoas_asdadssad_das
I then used this username to create a new admin user in the N2 database in the normal way I would do in N2. Firstly, I need to add the relevant membership config for N2 into the web.config:
view sourceprint?01.
02.
<
membership
defaultProvider
=
"ContentMembershipProvider"
>
03.
<
providers
>
04.
<
clear
/>
05.
<
add
name
=
"ContentMembershipProvider"
type
=
"N2.Security.ContentMembershipProvider, N2.Security"
/>
06.
providers
>
07.
membership
>
08.
<
roleManager
enabled
=
"true"
defaultProvider
=
"ContentRoleProvider"
>
09.
<
providers
>
10.
<
clear
/>
11.
<
add
name
=
"ContentRoleProvider"
type
=
"N2.Security.ContentRoleProvider, N2.Security"
/>
12.
providers
>
13.
roleManager
>
14.
<
profile
defaultProvider
=
"ContentProfileProvider"
>
15.
<
providers
>
16.
<
clear
/>
17.
<
add
name
=
"ContentProfileProvider"
type
=
"N2.Security.ContentProfileProvider, N2.Security"
/>
18.
providers
>
19.
profile
>
Changeset reference 55352
Then, I temporarily replace the WCHM authentication configuration with the out-the-box default N2 authentication section:
view sourceprint?1.
<
authentication
mode
=
"Forms"
>
2.
<
forms
loginUrl
=
"edit/login.aspx"
protection
=
"All"
timeout
=
"30000"
path
=
"/"
>
3.
<
credentials
passwordFormat
=
"Clear"
>
4.
5.
<
user
name
=
"admin"
password
=
"changeme"
/>
6.
credentials
>
7.
forms
>
8.
authentication
>
I can now load up my site, browse to the /edit url and be presented with the standard N2 login screen.
Logging in with the default admin user specified in config gets me into the N2 admin interface:
Now we’re getting somewhere! I can then use the N2 users screen to add a new user – I use the Open ID username as the N2 username, and fill the rest of the details in, but in fact, they’re not going to be used as we’re going to rely on Open ID to authenticate us. Once the user is added, we can see it in the N2 users table:
Now that we have our first real admin user, we can replace the authentication section in web.config with the original WCHM Open ID config:
view sourceprint?1.
<
authentication
mode
=
"Forms"
>
2.
<
forms
defaultUrl
=
"~/"
loginUrl
=
"~/user/login"
timeout
=
"2880"
name
=
"__wchm_auth"
/>
3.
authentication
>
We can now log in and out of N2 using the Open ID authentication. If I try to browse to the /edit url in order to get to the admin site, I will get presented with the WCHM Open ID authentication screen. Once authenticated using Open ID, I can then access the edit site fine as the authenticated username matches an admin user of the same username in N2.
Next…
So, we’re practically there – we have a working site and a working N2 admin site which we can access using our Open ID authenticated username. The Home page still loads normally and is in fact being routed via the N2 content route. The final steps are to build up the content definitions, and pass the content from N2 to the view…