NullReferenceException when calling FindPagesWithCriteria() - episerver

I'm calling FindPagesWithCriteria(PageReference pageLink, PropertyCriteriaCollection criterias) on an injected DataFactory and I'm getting a NullReferenceException in DefaultPageCriteriaQueryService.GetProviderQueryService():
[NullReferenceException: Object reference not set to an instance of an
object.]
EPiServer.Core.DefaultPageCriteriaQueryService.GetProviderQueryService(ContentProvider
provider) +44
EPiServer.Core.DefaultPageCriteriaQueryService.FindPagesWithCriteriaInternal(PageReference
pageLink, PropertyCriteriaCollection criterias, String languageBranch,
ILanguageSelector selector, FindPagesWithCriteriaDelegate
findPagesDelegate) +293
EPiServer.Core.DefaultPageCriteriaQueryService.FindPagesWithCriteria(PageReference
pageLink, PropertyCriteriaCollection criterias, String languageBranch,
ILanguageSelector selector) +124
EPiServer.DataFactory.FindPagesWithCriteria(PageReference pageLink,
PropertyCriteriaCollection criterias) +115
...
I've hooked up the Episerver symbol servers and stepped through the code, dee down in DefaultPageCriteriaQueryService I can see the ContentProvider being passed to GetProviderQueryService() is null leading to the NRE. The line calling this method is this:
case TypeOfSearch.Local:
return findPagesDelegate(pageLink, tempCriteria, languageBranch, selector, this.GetProviderQueryService(this._providerManager.ProviderMap.GetDefaultProvider()));
with the culprit being that _providerManager.ProviderMap.GetDefaultProvider() returns null because _providerManager.ProviderMap is empty. I've never experienced this issue before and I can't find any relevant information about the ProviderMap if it should be initialised.
Why am I experiencing this issue? Why is my ProviderMap empty? Should my ProviderMap have a default provider?

I don't think you can inject DataFactory since it's a singleton. You can however inject EPiServer.Core.IPageCriteriaQueryService instead which has the FindPagesWithCriteria method.

As #Andreas alludes to, it's an issue with the dependency injection. I've added the following type bindings to my IConfigurableModule and everything works fine now:
cfg.For<DataFactory>().Use(() => DataFactory.Instance);
cfg.For<IContentRepository>().Use(() => DataFactory.Instance);
cfg.For<IContentLoader>().Use(() => DataFactory.Instance);

Related

SQL Server 2012 assembly execution failure - System.NullReferenceException: Object reference not set to an instance of an object

I am trying to execute a UDF which uses a CLR assembly. Each time I try to run it I get the below error:
Msg 6522, Level 16, State 1, Line 45
A .NET Framework error occurred during execution of user-defined routine or aggregate "Geocode":
System.NullReferenceException: Object reference not set to an instance of an object.
at ProSpatial.UserDefinedFunctions.GeocodeUDF(SqlString countryRegion, SqlString adminDistrict, SqlString locality, SqlString postalCode, SqlString addressLine)
It is a geocoding assembly, which is based on the below blog:
https://alastaira.wordpress.com/2012/05/04/geocoding-in-sql-server-with-the-bing-maps-locations-api/
Is there anything I can do to fix it? It was working fine, but just stopped working recently. I changed the Bing Maps key to a new one, but that hasn't resolved the issue. Anyone have any ideas?
Cheers
Edit: I entered a formatted URL into Chrome, to see if I can get the error. I entered the below URL format:
http://dev.virtualearth.net/REST/v1/Locations?countryRegion={0}&adminDistrict={1}&locality={2}&postalCode={3}&addressLine={4}&key={5}&output=xml
All I did was to replace items 0 to 5 with their respective entries. I left the curly brackets in there, and then also tried it without the curly brackets. Without the curly brackets, the URL returned a result with no issues.
In the browser, I am getting geocoded results, but not in SQL any more
Just worked it out. One of the address fields that was being geocoded was null in the database, and the API did not like that. So I removed that from the geocoding list
Looking at the code in that blog, if you are passing in a NULL, then it's not the API that's throwing the error. The error is happening because NULL values are not being handled when the method is first called. The code just casts the SqlString input parameters to string without first checking to see if there is a value in the SqlString variable. SqlString is very similar to a nullable string.
Fortunately, it is rather easy to adjust the code to properly handle NULL values in the input parameters. Starting with a redacted snippet of the original code below, I will show how to do this for one parameter and you can repeat that modification for the others (well, the ones that might actually be NULL in the DB; no need to do this for parameters that are guaranteed to be there due to being in a NOT NULL column).
public static SqlGeography GeocodeUDF(
SqlString countryRegion,
SqlString adminDistrict,
SqlString locality,
SqlString postalCode,
SqlString addressLine
)
{
...
string localAdminDistrict = string.Empty;
if (!adminDistrict.IsNull)
{
localAdminDistrict = adminDistrict.Value;
}
// Attempt to geocode the requested address
try
{
geocodeResponse = Geocode(
(string)countryRegion,
localAdminDistrict,
(string)locality,
(string)postalCode,
(string)addressLine
);
}
All I did was:
Added a local variable for localAdminDistrict, defaulted to an empty string.
Added an if block to set localAdminDistrict if adminDistrict is not null.
Updated the call to Geocode() to use localAdminDistrict instead of (string)adminDistrict.
This should work as long as the Bing Maps API is ok with an empty value for adminDistrict (i.e. ...&adminDistrict=&locality=... ), as opposed to adminDistrict not being present in the GET request (which is easy enough, it just requires an additional modification).
ALSO: As long as you are going to be in there updating the code, you really should move the calls to the Close() and Dispose() methods into a finally block for that try / catch.
For more info on working with SQLCLR in general, please visit: SQLCLR Info

bug with IEntity.toString()?

There seem to be a bug with calling .toString() on an entity created by createQueryEntity. If you use it in a query. It will have some garbage string "tring" in it.
IEntity queryEntity = (IEntity) GenerateQuery.createQueryEntity(Vendor.class);
queryEntity.toString();
Calendar start = Calendar.getInstance();
start.add(Calendar.YEAR, -1);
Vendor vendor = (Vendor) queryEntity ;
return select($(vendor))
.where($(vendor.getMetaData().getLastUpdatedTime()).gte(start))
.where($(vendor.isActive()).eq(false))
.skip(1).take(1000)
.generate();
This would result to something like "select tring.tring.* from ..." Has anyone else seen this?
Finally figured it out. Apparently you can't call any methods on the queryEntity returned by createQueryEntity BEFORE calling select(). That means toString() or ((Vendor) queryEntity).isActive() shouldn't be called before select ($(vendor)).
The solution is to store the results of select($(vendor)) first before calling these methods.
Be careful when debugging because adding a watch expression will call toString() too.

Error with ibatis sql iterate

I'm using ibatis + DWR , but when i pass a map to ibatis i will get an error as below:
Cause: com.ibatis.sqlmap.client.SqlMapException: ParameterObject or
property was not a Collection, Array or Iterator.
here is my sql:
<update id="updateDarenFlagByUserTagIDs" parameterClass="java.util.Map">
update system_usertag
set isdaren = 1
where uid = #uid#
<isNotEmpty prepend=" AND " property="utidlist">
and utid in
<iterate open="(" close=")" conjunction="," property="utidlist">
#utidlist[]#
</iterate>
</isNotEmpty>
</update>
and here in the DWR part, i passed a map as below:
{'uid':uid, 'utidlist':utidlist}
Any ideas on this error?
I have answered the exact same question in the following post https://stackoverflow.com/questions/18997883/malformed-url-exception-in-ibatis/19025819#19025819 do make reference to it. The solution to your problem is very simple, ensure that the argument nested in your iterate tag <iterate></iterate> which in your case is "utidlist" is indeed a list/collection and nothing but a list. The cause of this error is that your iterable property "utidlist" isn't a list. If you can get it to be a list and not a flat value you'll just be fine.
Just in case you can still get it to work you may also want to paste a full stack of your logs so that you can see what is going wrong.

Set property on body using bean()

I'm trying to set a property called "articleId" on the exchange's body and I thought the most explicit way to do this would be to use bean(). However, I can't get it to work. When I have the following in my route:
.bean(body(Article.class), "setArticleId(${header.articleId})")
I get this error message:
Caused by: org.apache.camel.component.bean.MethodNotFoundException: Method with name: setArticleId(${header.articleId}) not found on bean: bodyAs[com.example.model.Article] of type: org.apache.camel.builder.ValueBuilder
My solution has been to use a processor() and a few lines of code in order to set the articleId property from the header value, but to me that seems like overkill.
I've been complaining on camel-users that there isn't a good way to do this. For now here is how I tackle it:
.setHeader("dummy").ognl("request.body.articleId = request.headers.articleId")
Which requires adding camel-ognl dependency.
UPDATE
Actually, there is also a language endpoint that can do this without the setHeader, but you have to say transform=false or else it replaces your body with the result:
.to("language:ognl:request.body.articleId = request.headers.articleId?transform=false") // remember ?transform=false
I think you need to spend some time to go through this page, if you don't know how to tell camel which method of the bean you want it invoke.
If you just want to set the exchange property, you can just use the DSL
setProperty("articleId", body());
to do this kind of work.

Configure Interception with Unity AutoConfig in VB.NET

I'm trying to get interception working in vb.net since my work only allows that. The way I would use it is to configure say some logger so that every business logic function that gets run is intercepted and logged to the database (bad idea, but its just an example). This is an example that I found:
container
.ConfigureAutoRegistration()
.Include(If.Implements<IBusinessService>, (x, y) =>
{
if (x.IsClass)
y.Configure<Interception>().
SetDefaultInterceptorFor(x,new VirtualMethodInterceptor());
})
This is what I tried to get working in vb.net, but it keeps throwing an error.
container.
ConfigureAutoRegistration().
Include([if].ImplementsITypeName, Function(x, y)
if x.IsClass
y.Configure(of Interception)()
.SetDefaultInterceptorFor(x,new VirtualMethodInterceptor())
End Function)
The error is:
Argument not specified for parameter 'type' of 'Public Shared Function ImplementsITypeName(type as System.Type) As Boolean.
Now obviously I need to specify some type, but the point is that I need to autoregister, so why do I need to provide a type? Also, the C# code doesn't require it, and neither does the code sample (see below).
var container = new UnityContainer();
container
.ConfigureAutoRegistration()
.ExcludeAssemblies(a => a.GetName().FullName.Contains("Test"))
.Include(If.Implements<ILogger>, Then.Register().UsingPerCallMode())
.Include(If.ImplementsITypeName, Then.Register().WithTypeName())
.Include(If.Implements<ICustomerRepository>, Then.Register().WithName("Sample"))
.Include(If.Implements<IOrderRepository>,
Then.Register().AsSingleInterfaceOfType().UsingPerCallMode())
.Include(If.DecoratedWith<LoggerAttribute>,
Then.Register()
.As<IDisposable>()
.WithTypeName()
.UsingLifetime<MyLifetimeManager>())
.Exclude(t => t.Name.Contains("Trace"))
.ApplyAutoRegistration();
http://autoregistration.codeplex.com/
I ended up using structure map.

Resources