Setup EPiServer Search in a future safe and stable way
In almost every project I have done where I have the solution in a load balanced way I have had problem with EPiServer Search. Now I have figured out a way to set it up so the problems are nearly gone. This is also the way you must set it up if you would like to move your solution to Microsoft Azure.
I start out this example by creating a new Alloy project with the extension inside Visual Studio. That gives me a MVC project with EPiServer Search that are setup and will work if I press F5. I have now a solution that looks like this:
Inside web.config EPiServer Search are configured like this:
<episerver.search active="true"> <namedIndexingServices defaultService="serviceName"> <services> <add name="serviceName" baseUri="http://localhost:27565/IndexingService/IndexingService.svc" accessKey="local" /> </services> </namedIndexingServices> <searchResultFilter defaultInclude="true"> <providers /> </searchResultFilter> </episerver.search> <episerver.search.indexingservice> <clients> <add name="local" description="local" allowLocal="true" readonly="false" /> </clients> <namedIndexes defaultIndex="default"> <indexes> <add name="default" directoryPath="[appDataPath]\Index" readonly="false" /> </indexes> </namedIndexes> </episerver.search.indexingservice>
This is the basic way of configure EPiServer Search and it will work for small projects that are not in a load balanced environment or on Microsoft Azure. The problem with having this configuration in production in a load balanced environment is that if you put the index files on a common drive and let all the websites index then the index files will be corrupt. You can solve this by setting only one of the sites to do the index and that usually works, but I have had times when it fails because of for example problems with routing and so on.
The solution is to create another project inside your solution and when you create it be careful to not get to much example code in it. It should look something like this:
As you can see in the images, I create a empty site with no folders and core reference to anything. I do not create a test project to it and does not host it in the cloud (even if that would be possible)
After doing that I add the EPiServer Search nuget package to the new site and remove that package from the regular web site. I also add a App_data folder to the new site, so I have somewhere to save the indexing files. The solution then looks like this:
Now to get it to work we need to do a couple of things. We start by locating these lines in the regular web site and remove them (the nuget package are great at adding stuff but not removing them).
<section name="episerver.search.indexingservice" type="EPiServer.Search.IndexingService.Configuration.IndexingServiceSection, EPiServer.Search.IndexingService" /> <dependentAssembly> <assemblyIdentity name="EPiServer.Search.IndexingService" publicKeyToken="8fe83dea738b45b7" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-126.96.36.199" newVersion="188.8.131.52" /> </dependentAssembly> <episerver.search.indexingservice> <clients> <add name="local" description="local" allowLocal="true" readonly="false" /> </clients> <namedIndexes defaultIndex="default"> <indexes> <add name="default" directoryPath="[appDataPath]\Index" readonly="false" /> </indexes> </namedIndexes> </episerver.search.indexingservice> <location path="IndexingService/IndexingService.svc"> <system.web> <httpRuntime maxQueryStringLength="65536" /> </system.web> <system.webServer> <security> <requestFiltering> <requestLimits maxQueryString="65536" /> </requestFiltering> </security> </system.webServer> </location>
Then open up Web.Config inside the new project that contains EPiServer Search and change this line:
<add name="default" directoryPath="[appDataPath]\Index" readonly="false" /> to
<add name="default" directoryPath="App_Data\Index" readonly="false" />
Then find this part
<clients> <add name="local" description="local" allowLocal="true" readonly="false" /> </clients>
And change to this:
<clients> <add name="C7184E3ED7134895B3E95AB3AB4F4AE5" description="local" allowLocal="false" ipAddress="0.0.0.0/0" ip6Address="::/0" readonly="false" /> </clients>
As you can see the name is a pretty much unique string and I changed allowLocal to false and added settings for ipv4 och ipv6 that basicly says allow all. You can read more here on why to add this settings: http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-CMS/8/Search/Installing-and-deploying-Search-Service/.
Now you need to go back to the web.config for the regular web project and find the line that points out the endpoint to the indexing asmx, should look something like this:
<add name="serviceName" baseUri="http://localhost:27565/IndexingService/IndexingService.svc" accessKey="local" />
First change the accessKey to match the pretty much unique name you selected before and then change the baseUri so it match the uri you have to your search project. For me it become like this:
<add name="serviceName" baseUri="http://localhost:28217/IndexingService/IndexingService.svc" accessKey="C7184E3ED7134895B3E95AB3AB4F4AE5" />
Now you should be pretty much up and running for the developer part. Start debug or make shore that you start up both web projects and then go into this url:
Make shore you check Delete old data and then press Start Indexing.
This will reindex all your site the new index.
Important: If you do this in Visual Studio 2015 and you get an error like this when browsing to http://localhost:28217/IndexingService/IndexingService.svc:
Could not find a part of the path 'C:\.....\EPiServerSite.EPiServerSearch\bin\roslyn\csc.exe'. just do like they say here:
It is a bug in VS2015
When you deploy this to production you need to prepare by creating a new website on one of your servers and then either go by port or by a hostname to reach it from all the other servers.
In my example I create one with a host name since I only have port 80 and 443 open in the firewall so I can not reach the iis from outside the server on any other port. So for example create a site like this:
Then I will add a transformation for my web.config in my regular site like this:
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 --> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <episerver.search active="true"> <namedIndexingServices defaultService="serviceName"> <services> <add name="serviceName" baseUri="http://EPiServerSite.EPiServerSearch/IndexingService/IndexingService.svc" accessKey="C7184E3ED7134895B3E95AB3AB4F4AE5" xdt:Transform="Replace" /> </services> </namedIndexingServices> </episerver.search> </configuration>
This will not work out of the box since the servers does not know how to translate the "url" EPiServerSite.EPiServerSearch to an ip-adress so we need to tell them that. To do this, open up a notepad as a administrator on the servers and navigate to this file:
It has not file suffix so you need to change in notepad to show all files to see the file hosts. In it on the server that contains the search site add a line like this:
And on the other servers add a similar line but change 127.0.0.1 (that means localhost) to the ipaddress of the server containing the search site.
This works great for me and I have saved myself a lot of problems by doing like this.