There is no index named: TicketsByPaymentTotal - indexing

I have written a code for index creation but when i run the application and try to call it then give a error of 'There is no index named'. My code is as follow :
I have created a class for index creation like :
public class TicketsByPaymentTotal : AbstractIndexCreationTask<Tickets,TicketTotal>
{
public TicketsByPaymentTotal()
{
Map = docs => from doc in docs
select new
{
TicketId = doc.TicketData.ID,
TicketTotalVal = doc.TicketData.PaymentTotal,
TotalVal = doc.TicketData.Total
};
Reduce = results => from result in results
group result by result.TicketId
into g
select new
{
TicketId = g.Key,
TicketTotalVal = g.Sum(x => x.TicketTotalVal),
TotalVal = g.Sum(x => x.TotalVal)
};
}
}
and i am creating index in global.asax file like :
public class MvcApplication : System.Web.HttpApplication
{
public IDocumentSession DocSession;
//DocumentStore store = new DocumentStore{ConnectionStringName="RavenDB2",DefaultDatabase="Dinerware"};
protected void Application_Start()
{
//AreaRegistration.RegisterAllAreas();
DataDocumentStore.Initialize();
DocSession = DataDocumentStore.Instance.OpenSession("Dinerware");
RegisterRoutes(RouteTable.Routes);
//store.Initialize();
HandlerConfig.RegisterHandlers(GlobalConfiguration.Configuration.MessageHandlers);
IndexCreation.CreateIndexes(typeof(TicketsByPaymentTotal).Assembly,DocSession.Advanced.DocumentStore);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller="Home",action="Index",id=""});
}
}
How to solve this issue.
Thanks.
Regards,
sandy

You are creating the index in the system database, even though you are using a named instance called "Dinnerware".
If you want to use a named database, pass it in the DefaultDatabase parameter when you create the document store instance.
Don't pass the name when you are opening the session. That should be reserved for when you have multi-database needs.
You should just pass your document store instance into the CreateIndexes method directly, rather than pulling it out of session.
Don't open a session and assign it to a property. Sessions are meant to be short lived, and must be disposed. Only the document store should be long lived on a single instance. Usually, sessions are created in a using statement. In a web app, a new session should be created for each and every web request.

Related

Remove route from RouteCollection in Asp.Net Core and add new with same route name (nopCommerce-4.00)

I want to remove existing route from RouteCollection and want to add new route with same route name in nopCommerce 4.00 via plugin
Existing route name:
//home page
routeBuilder.MapLocalizedRoute("HomePage", "",
new { controller = "Home", action = "Index" });
I Want to replace it with
routeBuilder.MapLocalizedRoute("HomePage", "",
new { controller = "CustomPage", action = "Homepage" });
I tried several ways but not get any luck.
In my case, I have to replace the robots.txt generation.
I created a new public controller in my plugin, and I copy the original action here:
public class MiscCommonController : BasePublicController
{
#region Fields
private readonly ICommonModelFactory _commonModelFactory;
#endregion Fields
#region Ctor
public MiscCommonController(
ICommonModelFactory commonModelFactory
)
{
this._commonModelFactory = commonModelFactory;
}
#endregion Ctor
#region Methods
//robots.txt file
//available even when a store is closed
[CheckAccessClosedStore(true)]
//available even when navigation is not allowed
[CheckAccessPublicStore(true)]
public virtual IActionResult RobotsTextFile()
{
var robotsFileContent = _commonModelFactory.PrepareRobotsTextFile();
return Content(robotsFileContent, MimeTypes.TextPlain);
}
#endregion Methods
}
After this I create a RouteProvider for my plugin, and I replaced the original route to my own one.
public partial class RouteProvider : IRouteProvider
{
/// <summary>
/// Gets a priority of route provider
/// </summary>
public int Priority => -1;
/// <summary>
/// Register routes
/// </summary>
/// <param name="routeBuilder">Route builder</param>
public void RegisterRoutes(IRouteBuilder routeBuilder)
{
Route route = null;
foreach (Route item in routeBuilder.Routes)
{
if (item.Name == "robots.txt")
{
route = item;
break;
}
}
if (route != null) routeBuilder.Routes.Remove(route);
routeBuilder.MapRoute(
"robots.txt",
"robots.txt",
new { controller = "MiscCommon", action = "RobotsTextFile" }
);
}
}
That's all.
After this implementation, the routing works fine, and the get request landed in my own controller, which is act like the original.
Now, I can replace the generation logic with my own.
I hope it helps.
in the RouteProvider.cs of your plugin write these codes (based on your names):
var lastExistingRoute= routeBuilder.Routes.FirstOrDefault(x => ((Route)x).Name == "HomePage");
routeBuilder.Routes.Remove(lastExistingRoute);
routeBuilder.MapRoute("HomePage", "",
new { controller = "CustomPage", action = "Homepage", });
and the below codes worked for myself version 4.20:
var lastDownloadRoute=routeBuilder.Routes.FirstOrDefault(x => ((Route)x).Name == "GetDownload");
routeBuilder.Routes.Remove(lastDownloadRoute);
routeBuilder.MapRoute("GetDownload", "download/getdownload/{guid}/{agree?}",
new { controller = "AzTechProduct", action = "GetPayed", });
There are two potential ways to deal with this in nopCommerce 4.3 that I see with a quick examination of the code.
First, you could create an IRouteProvider, add your route that has the same signature as the one you wish to 'delete' and make sure the Priority on the provider is greater than 1.
Doing this will basically override the default route built into Nop. This is my preferred method.
public partial class RouteProvider: IRouteProvider
{
public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
{
var pattern = string.Empty;
if (DataSettingsManager.DatabaseIsInstalled)
{
var localizationSettings = endpointRouteBuilder.ServiceProvider.GetRequiredService<LocalizationSettings>();
if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
{
var langservice = endpointRouteBuilder.ServiceProvider.GetRequiredService<ILanguageService>();
var languages = langservice.GetAllLanguages().ToList();
pattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/";
}
}
// Handle the standard request
endpointRouteBuilder.MapControllerRoute("Wishlist", pattern + "wishlist/{customerGuid?}",
new { controller = "MyShoppingCart", action = "Wishlist" });
return;
}
public int Priority => 100;
}
The key to the code above is the Priority value. This route will get added to the list first and will therefore take precedence over the default route. Using this technique eliminates the need to delete the default route.
The second possible method turns out to not work because the endpointRouteBuilder.DataSources[n].Endpoints collection is read only. So, as far as I know, you can't remove mappings from that list after they have been added.

Programmatically create index

How do I create an index programmatically in RavenDB?
I tried to follow this example.
This is my index creator:
public class MyIndex : Raven.Client.Indexes.AbstractIndexCreationTask<MyEntity>
{
public MyIndex()
{
Map = col => col.Select(c => new
{
code = c.Code,
len = c.Code.Length,
sub = c.Code.Substring(0, 1)
});
}
}
And here is the caller:
var store = new Raven.Client.Document.DocumentStore
{
Url = "http://localhost:8080"
};
store.Initialize();
try
{
using (var session = store.OpenSession("MyDB"))
{
Raven.Client.Indexes.IndexCreation.CreateIndexes(
typeof(MyIndex).Assembly, store);
}
}
finally
{
store.Dispose();
}
The index was created but not in MyDB but in system database.
How to create the index in MyDB? Is the way I create index correct?
Try this:
specify the database name in your store object
var store = new Raven.Client.Document.DocumentStore
{
Url = "http://localhost:8080",
DefaultDatabase = "MyDB"
};
As MED pointed out, you can provide a default database when attaching to the document store. When doing so, you no longer pass the database name to the OpenSession method. This is the easiest way, and if you're working with a single database then it is the best answer (and should be given the credit as the answer to this question).
But if you need to work with multiple databases, and thus can't use that technique, then you can use this helper method.
public static void CreateIndexes(Assembly assembly, IDocumentStore store,
string databaseName)
{
var catalog = new AssemblyCatalog(assembly);
var provider = new CompositionContainer(catalog);
var commands = store.DatabaseCommands.ForDatabase(databaseName);
IndexCreation.CreateIndexes(provider, commands, store.Conventions);
}
Call it the same way you would call the other method, but now you can pass the database name as a parameter.

Naming conventions for view pages and setting controller action for view

I am unsure on how I should be naming my View pages, they are all CamelCase.cshtml, that when viewed in the browser look like "http://www.website.com/Home/CamelCase".
When I am building outside of .NET my pages are named like "this-is-not-camel-case.html". How would I go about doing this in my MVC4 project?
If I did go with this then how would I tell the view to look at the relevant controller?
Views/Home/camel-case.cshtml
Fake edit: Sorry if this has been asked before, I can't find anything via search or Google. Thanks.
There are a few ways you can do this:
Name all of your views in the style you would like them to show up in the url
This is pretty simple, you just add the ActionName attribute to all of your actions and specify them in the style you would like your url to look like, then rename your CamelCase.cshtml files to camel-case.cshtml files.
Use attribute routing
Along the same lines as above, there is a plugin on nuget to enable attribute routing which lets you specify the full url for each action as an attribute on the action. It has convention attributes to help you out with controller names and such as well. I generally prefer this approach because I like to be very explicit with the routes in my application.
A more framework-y approach
It's probably possible to do something convention based by extending the MVC framework, but it would be a decent amount of work. In order to select the correct action on a controller, you'd need to map the action name on its way in to MVC to its CamelCase equivalent before the framework uses it to locate the action on the controller. The easiest place to do this is in the Route, which is the last thing to happen before the MVC framework takes over the request. You'll also need to convert the other way on the way out so the urls generated look like you want them to.
Since you don't really want to alter the existing method to register routes, it's probably best write a function in application init that loops over all routes after they have been registered and wraps them with your new functionality.
Here is an example route and modifications to application start that achieve what you are trying to do. I'd still go with the route attribute approach however.
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
WrapRoutesWithNamingConvention(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
private void WrapRoutesWithNamingConvention(RouteCollection routes)
{
var wrappedRoutes = routes.Select(m => new ConventionRoute(m)).ToList();
routes.Clear();
wrappedRoutes.ForEach(routes.Add);
}
private class ConventionRoute : Route
{
private readonly RouteBase baseRoute;
public ConventionRoute(RouteBase baseRoute)
: base(null, null)
{
this.baseRoute = baseRoute;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var baseRouteData = baseRoute.GetRouteData(httpContext);
if (baseRouteData == null) return null;
var actionName = baseRouteData.Values["action"] as string;
var convertedActionName = ConvertHyphensToPascalCase(actionName);
baseRouteData.Values["action"] = convertedActionName;
return baseRouteData;
}
private string ConvertHyphensToPascalCase(string hyphens)
{
var capitalParts = hyphens.Split('-').Select(m => m.Substring(0, 1).ToUpper() + m.Substring(1));
var pascalCase = String.Join("", capitalParts);
return pascalCase;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var valuesClone = new RouteValueDictionary(values);
var pascalAction = valuesClone["action"] as string;
var hyphens = ConvertPascalCaseToHyphens(pascalAction);
valuesClone["action"] = hyphens;
var baseRouteVirtualPath = baseRoute.GetVirtualPath(requestContext, valuesClone);
return baseRouteVirtualPath;
}
private string ConvertPascalCaseToHyphens(string pascal)
{
var pascalParts = new List<string>();
var currentPart = new StringBuilder();
foreach (var character in pascal)
{
if (char.IsUpper(character) && currentPart.Length > 0)
{
pascalParts.Add(currentPart.ToString());
currentPart.Clear();
}
currentPart.Append(character);
}
if (currentPart.Length > 0)
{
pascalParts.Add(currentPart.ToString());
}
var lowers = pascalParts.Select(m => m.ToLower());
var hyphens = String.Join("-", lowers);
return hyphens;
}
}
}

Delete Indexed In RavenDB not found

I am trying to write a generic delete function for multi tenant ravendb for integration testing the class is -
public class RavenDeleteAll
{
private readonly IDocumentStore _store;
private readonly string _testDataBase;
public RavenDeleteAll(string testDataBase, IDocumentStore store)
{
_testDataBase = testDataBase;
_store = store;
}
public void Clear<T>(string indexName)
{
using (var session = _store.OpenSession(_testDataBase))
{
session.Advanced.DocumentStore.DatabaseCommands.DeleteIndex(indexName);
session.Advanced.DocumentStore.DatabaseCommands.PutIndex(indexName, new IndexDefinitionBuilder<T>
{
Map = documents => documents.Select(entity => new { })
});
var indexDefinition = session.Advanced.DocumentStore.DatabaseCommands.GetIndex(indexName);
session.Advanced.LuceneQuery<T>(indexName)
.WaitForNonStaleResultsAsOfNow()
.Take(0)
.ToList();
session.Advanced.DatabaseCommands.DeleteByIndex(indexName, new IndexQuery());
}
}
}
Note that in the code i try to read back the index after putindex call for sanity check. but when I execute the index it throws an invalidoperationexception stating that /indexes/UTO does not exist?
Also from management console I can clearly see the index -
What am I not doing? Also the index is created under default database and not the actual database name?
It looks like you are creating the index in the Default database not the Tenant Database then asking the Tenant Database for that Index. You need to create the index in the database where you are going to use it. The following is not tested but should work for creating the index in the tenant database.
IDatabaseCommands context = session.Advanced.DocumentStore.DatabaseCommands.ForDatabase(database);
context.PutIndex(indexName, new IndexDefinitionBuilder<T>
{
Map = documents => documents.Select(entity => new { })
});

composing MEF parts in C# like a simple Funq container

In Funq and probably most other IoC containers I can simply do this to configure a type:
container.Register<ISomeThing>(c => new SomeThing());
How could I quickly extend MEF (or use existing MEF functionality) to do the same without using attributes.
Here is how I thought I could do it:
var container = new CompositionContainer();
var batch = new CompositionBatch();
batch.AddExport<ISomeThing>(() => new SomeThing());
batch.AddExportedValue(batch);
container.Compose(batch);
With this extension method for CompositionBatch:
public static ComposablePart AddExport<TKey>(this CompositionBatch batch, Func<object> func)
{
var typeString = typeof(TKey).ToString();
return batch.AddExport(
new Export(
new ExportDefinition(
typeString,
new Dictionary<string, object>() { { "ExportTypeIdentity", typeString } }),
func));
}
If I later do:
var a = container.GetExport<ISomeThing>().Value;
var b = container.GetExport<ISomeThing>().Value;
Both instance are the same. How can I force (configure) them to be different instances?
If this is not the way to go, how would I do this in MEF?
I would imagine the key is to add the delegate to the container, e.g.:
container.AddExportedValue<Func<ISomething>>(() => new Something());
That way you can grab the delegate and execute it:
var factory = container.GetExport<Func<ISomething>>();
ISomething something = factory();
Of course, MEF (Silverlight) does provide a native ExportFactory<T> (and ExportFactory<T,TMetadata> type that supports the creation of new instances for each call to import. You can add support for this by downloading Glen Block's ExportFactory for .NET 4.0 (Desktop) library.
If you don't want to use attributes, you can use this trick (based on Mark Seemann's blogpost).
First, create a generic class like this:
[PartCreationPolicy(CreationPolicy.NonShared)]
public class MefAdapter<T> where T : new()
{
private readonly T export;
public MefAdapter()
{
this.export = new T();
}
[Export]
public virtual T Export
{
get { return this.export; }
}
}
Now you can register any class you want in the container, like this:
var registeredTypesCatalog = new TypeCatalog(
typeof(MefAdapter<Foo>),
typeof(MefAdapter<Bar>),
...);
var container = new CompositionContainer(catalog);
Alternatively, you could implement your own export provider derived from ExportProvider, which allows you to pretty much duplicate Funq's way of working:
var provider = new FunqyExportProvider();
provider.Register<IFoo>(context => new Foo());
var container = new CompositionContainer(provider);
Both instance are the same. How can I force (configure) them to be different instances?
Simply mark the SomeThing class like this:
[Export(typeof(ISomeThing)]
[PartCreationPolicy(CreationPolicy.NonShared]
public class SomeThing : ISomeThing
{
...
}
And then you will get different instances wherever you import ISomeThing.
Alternatively, you can also set a required creation policy on an import:
[Export(typeof(IFoo))]
public class Foo : IFoo
{
[Import(typeof(ISomeThing),
RequiredCreationPolicy = CreationPolicy.NonShared)]
public ISomething SomeThing { private get; set; }
}
In Glen Block's Skydrive directory linked to in Matthew Abbott's answer I found something that seems simple and lightweight: A FuncCatalog. Download it here: FuncCatalogExtension.
Using the few little classes from that project I could now do this:
var funcCatalog = new FuncCatalog();
funcCatalog.AddPart<ISomeThing>(ep => new SomeThing());
var container = new CompositionContainer(funcCatalog);
var batch = new CompositionBatch();
batch.AddExportedObject<ExportProvider>(container);
container.Compose(batch);
var a = container.GetExportedObject<ISomeThing>();
var b = container.GetExportedObject<ISomeThing>();