created container extension for search/lucene stuff, modified namespaces to stay in alignment with Portoa

This commit is contained in:
tmont 2011-02-26 04:29:21 +00:00
parent a0c0c6791e
commit 5e15232192
12 changed files with 99 additions and 87 deletions

View File

@ -0,0 +1,76 @@
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Reflection;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Store;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using Portoa.Lucene;
using Portoa.Persistence;
using Portoa.Search;
using Portoa.Web.Unity;
using Portoa.Web.Unity.Lifetime;
using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Search;
using Directory = Lucene.Net.Store.Directory;
using Version = Lucene.Net.Util.Version;
namespace VideoGameQuotes.Web.Configuration {
public class EnableSearchWithLucene : UnityContainerExtension {
protected override void Initialize() {
var indexWriterLifetimeManager = new ExplicitlyDisposableLifetimeManager<IndexWriter>(
new ContainerControlledLifetimeManager(),
indexWriter => indexWriter.Close()
);
Container
.RegisterType<Directory>(new ContainerControlledLifetimeManager(), new InjectionFactory(CreateIndexDirectory))
.RegisterType<IndexWriter>(indexWriterLifetimeManager, new InjectionFactory(CreateIndexWriter))
.RegisterInstance(Version.LUCENE_29)
.RegisterType<Analyzer, StandardAnalyzer>(new InjectionConstructor(typeof(Version)))
.RegisterType<QueryParser>(new InjectionFactory(CreateQueryParser))
.RegisterAndIntercept(typeof(ISearcher<>), typeof(LuceneEntitySearcher<>))
.RegisterAndIntercept(typeof(ISearchService<>), typeof(SearchService<>))
.RegisterAndIntercept<ILuceneDocumentHandler<Quote>, QuoteDocumentHandler>()
.RegisterAndIntercept(typeof(ISearchIndexBuilder<>), typeof(LuceneEntityIndexBuilder<>));
Container
.Configure<Interception>()
.AddPolicy("UpdateSearchIndexPolicy")
.AddCallHandler<UpdateSearchIndexCallHandler>()
.AddMatchingRule<QuoteUpdatedMatchingRule>();
}
#region lucene-related factories
private static QueryParser CreateQueryParser(IUnityContainer container) {
return new QueryParser(container.Resolve<Version>(), "text", container.Resolve<Analyzer>());
}
private static Directory CreateIndexDirectory(IUnityContainer container) {
var indexDirectory = ((NameValueCollection)ConfigurationManager.GetSection("vgquotes"))["luceneIndexDirectory"];
return new SimpleFSDirectory(new DirectoryInfo(indexDirectory));
}
private static IndexWriter CreateIndexWriter(IUnityContainer container) {
return new IndexWriter(
container.Resolve<Directory>(),
new StandardAnalyzer(Version.LUCENE_29),
true,
IndexWriter.MaxFieldLength.UNLIMITED
);
}
#endregion
public class QuoteUpdatedMatchingRule : IMatchingRule {
private static readonly MethodBase saveMethod = typeof(IRepository<Quote, int>).GetMethod("Save", new[] { typeof(Quote) });
public bool Matches(MethodBase member) {
return member == saveMethod;
}
}
}
}

View File

@ -1,37 +1,19 @@
using System.Reflection;
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension; using Microsoft.Practices.Unity.InterceptionExtension;
using Portoa.Persistence;
using Portoa.Search; using Portoa.Search;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Configuration { namespace VideoGameQuotes.Web.Configuration {
/// <summary>
public class UpdateSearchIndex : UnityContainerExtension { /// Call handler that updates the index for a quote whenever it's updated
protected override void Initialize() { /// </summary>
Container
.Configure<Interception>()
.AddPolicy("UpdateSearchIndexPolicy")
.AddCallHandler<UpdateSearchIndexCallHandler>()
.AddMatchingRule<QuoteUpdatedMatchingRule>();
}
}
public class QuoteUpdatedMatchingRule : IMatchingRule {
private static readonly MethodBase saveMethod = typeof(IRepository<Quote, int>).GetMethod("Save", new[] { typeof(Quote) });
public bool Matches(MethodBase member) {
return member == saveMethod;
}
}
public class UpdateSearchIndexCallHandler : ICallHandler { public class UpdateSearchIndexCallHandler : ICallHandler {
private readonly IUnityContainer container; private readonly IUnityContainer container;
/// <remarks> /// <remarks>
/// Can't inject ISearchIndexBuilder because it causes an infinite loop /// Can't inject ISearchIndexBuilder because it causes an infinite loop
/// while trying to instantiate the call handler. So we do a later resolve /// while trying to instantiate the call handler. So we do a later resolve
/// on the index builder so that this shit fucking works. /// using the container on the index builder so that this shit fucking works.
/// </remarks> /// </remarks>
public UpdateSearchIndexCallHandler(IUnityContainer container) { public UpdateSearchIndexCallHandler(IUnityContainer container) {
this.container = container; this.container = container;

View File

@ -2,9 +2,9 @@
using System.Net; using System.Net;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Persistence; using Portoa.Persistence;
using Portoa.Web;
using Portoa.Web.ErrorHandling; using Portoa.Web.ErrorHandling;
using Portoa.Web.Results; using Portoa.Web.Results;
using Portoa.Web.Security;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models; using VideoGameQuotes.Web.Models;
using VideoGameQuotes.Web.Security; using VideoGameQuotes.Web.Security;
@ -121,7 +121,7 @@ namespace VideoGameQuotes.Web.Controllers {
adminService.SaveUser(user); adminService.SaveUser(user);
return View("PasswordSuccessfullyChanged"); return View("PasswordSuccessfullyChanged");
} catch { } catch {
ControllerContext.AddModelError("password", "Unable to change password"); ModelState.AddModelError("password", "Unable to change password");
return View(model); return View(model);
} }

View File

@ -3,8 +3,8 @@ using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Persistence; using Portoa.Persistence;
using Portoa.Util; using Portoa.Util;
using Portoa.Web;
using Portoa.Web.Controllers; using Portoa.Web.Controllers;
using Portoa.Web.Security;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models; using VideoGameQuotes.Web.Models;
using VideoGameQuotes.Web.Security; using VideoGameQuotes.Web.Security;

View File

@ -5,9 +5,9 @@ using System.Web.Mvc;
using Portoa.Persistence; using Portoa.Persistence;
using Portoa.Search; using Portoa.Search;
using Portoa.Validation.DataAnnotations; using Portoa.Validation.DataAnnotations;
using Portoa.Web;
using Portoa.Web.Controllers; using Portoa.Web.Controllers;
using Portoa.Web.Results; using Portoa.Web.Results;
using Portoa.Web.Security;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models; using VideoGameQuotes.Web.Models;
using VideoGameQuotes.Web.Security; using VideoGameQuotes.Web.Security;

View File

@ -1,20 +1,7 @@
using System.Collections.Specialized; using System.Web.Mvc;
using System.Configuration;
using System.IO;
using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index; using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using Portoa.Logging;
using Portoa.Lucene;
using Portoa.Persistence;
using Portoa.Search; using Portoa.Search;
using Portoa.Web; using Portoa.Web;
using Portoa.Web.Models; using Portoa.Web.Models;
@ -26,14 +13,11 @@ using VideoGameQuotes.Api.Persistence;
using VideoGameQuotes.Web.Configuration; using VideoGameQuotes.Web.Configuration;
using VideoGameQuotes.Web.Controllers; using VideoGameQuotes.Web.Controllers;
using VideoGameQuotes.Web.Models; using VideoGameQuotes.Web.Models;
using VideoGameQuotes.Web.Search;
using VideoGameQuotes.Web.Security; using VideoGameQuotes.Web.Security;
using VideoGameQuotes.Web.Services; using VideoGameQuotes.Web.Services;
using Directory = Lucene.Net.Store.Directory;
namespace VideoGameQuotes.Web { namespace VideoGameQuotes.Web {
public class MvcApplication : MvcApplicationBase<User> { public class MvcApplication : MvcApplicationBase<User> {
protected override void ConfigureModelBinders(ModelBinderDictionary binders) { protected override void ConfigureModelBinders(ModelBinderDictionary binders) {
binders binders
.Add<Region, FlagEnumModelBinder<Region>>() .Add<Region, FlagEnumModelBinder<Region>>()
@ -41,18 +25,13 @@ namespace VideoGameQuotes.Web {
.Add<ApiModel, ApiModelBinder>(); .Add<ApiModel, ApiModelBinder>();
} }
protected override void ConfigureUnityExtensions() { protected override void ConfigureUnity() {
Container Container
.AddNewExtension<ConfigureLog4Net>() .AddNewExtension<ConfigureLog4Net>()
.Configure<ILog4NetConfigurator>() .Configure<ILog4NetConfigurator>()
.SetName("VideoGameQuotes.Web") .SetName("VideoGameQuotes.Web")
.UseXml(); .UseXml();
Container.AddNewExtension<LogAllMethodCalls>();
Container.AddNewExtension<UpdateSearchIndex>();
}
protected override void ConfigureUnity() {
Container Container
.RegisterType<VerifyUserAttribute>(new InjectionProperty<VerifyUserAttribute>(attr => attr.UserProvider)) .RegisterType<VerifyUserAttribute>(new InjectionProperty<VerifyUserAttribute>(attr => attr.UserProvider))
.RegisterAndIntercept<ICurrentUserProvider<User>, SessionBasedUserProvider>() .RegisterAndIntercept<ICurrentUserProvider<User>, SessionBasedUserProvider>()
@ -65,45 +44,19 @@ namespace VideoGameQuotes.Web {
.RegisterAndIntercept<IGameService, GameService>() .RegisterAndIntercept<IGameService, GameService>()
.RegisterAndIntercept<IApiService, ApiService>() .RegisterAndIntercept<IApiService, ApiService>()
.RegisterAndIntercept<IAuthenticationService, FormsAuthenticationService>() .RegisterAndIntercept<IAuthenticationService, FormsAuthenticationService>()
.RegisterAndIntercept<IUserRepository, UserRepository>(); .RegisterAndIntercept<IUserRepository, UserRepository>()
.AddNewExtension<LogAllMethodCalls>()
//search stuff .AddNewExtension<EnableSearchWithLucene>();
Container
.RegisterType<Directory>(new ContainerControlledLifetimeManager(), new InjectionFactory(CreateIndexDirectory))
.RegisterType<IndexWriter>(new ContainerControlledLifetimeManager(), new InjectionFactory(CreateIndexWriter))
.RegisterInstance(Version.LUCENE_29)
.RegisterType<Analyzer, StandardAnalyzer>(new InjectionConstructor(typeof(Version)))
.RegisterType<QueryParser>(new InjectionFactory(CreateQueryParser))
.RegisterAndIntercept(typeof(ISearcher<>), typeof(LuceneEntitySearcher<>))
.RegisterAndIntercept(typeof(ISearchService<>), typeof(SearchService<>))
.RegisterAndIntercept<ILuceneDocumentHandler<Quote>, QuoteDocumentHandler>()
.RegisterAndIntercept(typeof(ISearchIndexBuilder<>), typeof(LuceneEntityIndexBuilder<>));
} }
#region lucene-related factories
private static QueryParser CreateQueryParser(IUnityContainer container) {
return new QueryParser(container.Resolve<Version>(), "text", container.Resolve<Analyzer>());
}
private static Directory CreateIndexDirectory(IUnityContainer container) {
var indexDirectory = ((NameValueCollection)ConfigurationManager.GetSection("vgquotes"))["luceneIndexDirectory"];
return new SimpleFSDirectory(new DirectoryInfo(indexDirectory));
}
private static IndexWriter CreateIndexWriter(IUnityContainer container) {
return new IndexWriter(
container.Resolve<Directory>(),
new StandardAnalyzer(Version.LUCENE_29),
true,
IndexWriter.MaxFieldLength.UNLIMITED
);
}
#endregion
protected override void AfterStartUp() { protected override void AfterStartUp() {
Container.Resolve<ISearchIndexBuilder<Quote>>().BuildIndex(); Container.Resolve<ISearchIndexBuilder<Quote>>().BuildIndex();
} }
protected override void OnApplicationEnd() {
Container.Resolve<IndexWriter>().Close();
}
protected override void RegisterRoutes(RouteCollection routes) { protected override void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("media/{*anything}"); routes.IgnoreRoute("media/{*anything}");

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Web; using Portoa.Web.Util;
namespace VideoGameQuotes.Web.Models { namespace VideoGameQuotes.Web.Models {
public class ApiModel { public class ApiModel {

View File

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Web; using Portoa.Web.Util;
namespace VideoGameQuotes.Web.Models { namespace VideoGameQuotes.Web.Models {
public class BrowseModelBinder : IModelBinder { public class BrowseModelBinder : IModelBinder {

View File

@ -4,7 +4,6 @@ using Portoa.Persistence;
using Portoa.Search; using Portoa.Search;
namespace VideoGameQuotes.Web.Search { namespace VideoGameQuotes.Web.Search {
public class SearchService<T> : ISearchService<T> where T : Entity<T, int> { public class SearchService<T> : ISearchService<T> where T : Entity<T, int> {
private readonly IRepository<T> repository; private readonly IRepository<T> repository;

View File

@ -1,5 +1,5 @@
using System.Web; using System.Web;
using Portoa.Web; using Portoa.Web.Security;
using Portoa.Web.Session; using Portoa.Web.Session;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
using VideoGameQuotes.Api.Persistence; using VideoGameQuotes.Api.Persistence;

View File

@ -1,7 +1,8 @@
using System.Net; using System.Net;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Web;
using Portoa.Web.ErrorHandling; using Portoa.Web.ErrorHandling;
using Portoa.Web.Security;
using Portoa.Web.Unity;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Security { namespace VideoGameQuotes.Web.Security {

View File

@ -81,6 +81,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Configuration\EnableSearchWithLucene.cs" />
<Compile Include="Configuration\UpdateSearchIndexCallHandler.cs" /> <Compile Include="Configuration\UpdateSearchIndexCallHandler.cs" />
<Compile Include="Controllers\AdminController.cs" /> <Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\ApiController.cs" /> <Compile Include="Controllers\ApiController.cs" />