System.NullReferenceException Context.Item.Axes.SelectSingleItem - sitecore

I recently added the Sitecore WebAPI nuget package and have been getting null reference errors when hitting any controller method that makes a reference to my base settings item. My base settings item is defined as follows:
public static class ItemReferences
{
private const string _configurationItemQueryByName = ".//ancestor::*[##templateid='{{SOME_ID}}']/../Settings";
public static Item GetConfigurationItem()
{
return Context.Item.Axes.SelectSingleItem(_configurationItemQueryByName);
}
}
I'm guessing it has to do with this being in a static context but I don't want to take it out of a static context because it doesn't change and many pieces of the website use it.

You are getting an exception because Context.Item is always null on your controller.
Try to change it so it uses Context.Database.GetItem() to get your configuration item.

Related

VS 2017 Designer: Method not found

I have a windows form that contains a user control (each defined in separate assemblies). Both the form and the user control call an extension method on BindingList<>. The extension method is defined in a 3rd assembly. Everything compiles & runs fine.
However, if I try to open the form in Visual Studio 2017 designer, I get an error:
To prevent possible data loss before loading the designer, the following errors must be resolved:
Method not found: 'System.ComponentModel.BindingList1 KamaTrenda.Utilities.Lists.ListUtilities.AddReset(System.ComponentModel.BindingList1,
System.Collections.Generic.IEnumerable`1)'.
Call stack:
at System.ComponentModel.ReflectPropertyDescriptor.SetValue(Object
component, Object value) at
Microsoft.VisualStudio.Shell.Design.VsTargetFrameworkPropertyDescriptor.SetValue(Object
component, Object value) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializePropertyAssignStatement(IDesignerSerializationManager
manager, CodeAssignStatement statement,
CodePropertyReferenceExpression propertyReferenceEx, Boolean
reportError) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeAssignStatement(IDesignerSerializationManager
manager, CodeAssignStatement statement) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeStatement(IDesignerSerializationManager
manager, CodeStatement statement)
Commenting out the content of the setter of this property allows for opening the form in the designer:
public IList<IPosition> PositionsToDisplay
{
get { return myPositionsToDisplay.Select(x => x.Position).ToList(); }
set { myPositionsToDisplay.AddReset(value.Select(x => new PositionAdapter(x))); }
}
myPositionsToDisplay:
private readonly BindingList<PositionAdapter> myPositionsToDisplay = new SortableBindingList<PositionAdapter>();
And AddReset:
public static class ListUtilities
{
public static BindingList<T> AddReset<T>(this BindingList<T> list, IEnumerable<T> toAdd)
{
list.RaiseListChangedEvents = false;
foreach (T item in toAdd)
list.Add(item);
list.RaiseListChangedEvents = true;
list.ResetBindings();
return list; // for chaining
}
}
I have tried adding
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
to the definition of PositionsToDisplay, and it made no difference.
I tried rebuilding, manually deleting the contents obj & bin directories for all 3 projects, as well as the contents of AppData\Local\Microsoft\VisualStudio\15.0_6d397e1a\ProjectAssemblies, closing all open documents in VS 2017, closing the solution, and restarting Visual Studio, and it made no difference.
The .resx file of neither the form, nor the control, refer to the property.
The Designer.cs for the form had some code that seemed to be causing the issue:
this.control.PositionsToDisplay = ((System.Collections.Generic.IList<IPosition>)(resources.GetObject("control.PositionsToDisplay")));
Deleting this (presumably after adding DesignerSerializationVisibility.Hidden, so that it does not get re-generated) seemed to solve the issue.

Should instance fields access be synchronized in a Tapestry page or component?

If a page or component class has one instance field which is a non-synchronized object, f.ex. an ArrayList, and the application has code that structurally modifies this field, should the access to this field be synchronized ?
F.ex.:
public class MyPageOrComponent
{
#Persist
private List<String> myList;
void setupRender()
{
if (this.myList == null)
{
this.myList = new ArrayList<>();
}
}
void afterRender(MarkupWriter writer)
{
// Should this be synchronized ?
if (someCondition)
{
this.myList.add(something);
}
else
{
this.myList.remove(something);
}
}
}
I'm asking because I seem to understand that Tapestry creates only one instance of a page or component class and it uses this instance for all the connected clients (but please correct me if this is not true).
In short the answer is no, you don't have to because Tapestry does this for you. Tapestry will transform your pages and classes for you at runtime in such a way that wherever you interact with your fields, they will not actually be working on the instance variable but on a managed variable that is thread safe. The full inner workings are beyond me, but a brief reference to the transformation can be found here.
One warning, don't instantiate your page/component variables at decleration. I have seen some strange behaviour around this. So don't do this:
private List<String> myList = new ArrayList<String>;
Tapestry uses some runtime byte code magic to transform your pages and components. Pages and components are singletons but the properties are transformed so that they are backed by a PerThreadValue. This means that each request gets it's own copy of the value so no synchronization is required.
As suggested by #joostschouten you should never initialize a mutable property in the field declaration. The strange behaviour he discusses is caused beacause this will be shared by all requests (since the initializer is only fired once for the page/component singleton). Mutable fields should instead be initialized in a render method (eg #SetupRender)

Sitecore dynamic data source locations

I have some components in my Sitecore install that can be added to one of any multiple placeholders on a page. The data source location of the renderings of these components can change based on what placeholder they are added to the site. I started creating a processor like
<getRenderingDatasource>
<processor patch:after="*[#type='custom']" type="custom" />
</getRenderingDatasource>
The class is like
public class GetDynamicDataSourceLocations : GetDatasourceLocation
{
public void Process(GetRenderingDatasourceArgs args)
{
...
}
}
I can't get the placeholder that I'm trying to attach the rendering to. Is there any way I can get the placeholder or atleast the parent where the component is being added?
Thanks
It's a very good idea you have here, but the GetRenderingDatasourceArgs can't provide you with the data you need if you're configuring the allowed datasource locations on the placeholder.
I've searched through querystring & form variables and context items as well, but there is no reference to the placeholder available in the getRenderingDatasource pipeline.
I did come up with something that could be the solution, although it's a bit hacky.
Create a processor for the getPlaceholderRenderings. The GetPlaceholderRenderingsArgs will provide you with a placeholder key.
Store the key in a session variable (I don't know another way of transferring data between pipelines at this point)
Retrieve the key from the session in your getRenderingDatasource processor.
This is the code I used to test it:
// Add to the getRenderingDatasource pipeline.
public class GetPlaceholderKey
{
public void Process(GetPlaceholderRenderingsArgs args)
{
System.Web.HttpContext.Current.Session["Placeholder"] = args.PlaceholderKey;
}
}
// Add to the getRenderingDatasource pipeline.
public class GetAllowedDatasources
{
public void Process(GetRenderingDatasourceArgs args)
{
Debug.WriteLine(System.Web.HttpContext.Current.Session["Placeholder"]);
}
}
This works when you add a rendering to a placeholder, but I have not tested other scenarios.
I can imagine it would not work when you set the datasource of a rendering that is already placed in the placeholder.

android: cannot access method of custom list

I got the following problem:
I made a custom list CustomList which extends ArrayList and added a new method to it:
public class CustomList extends ArrayList<CustomObj> {
public CustomObj get(String searchName) {
...
}
}
now in my MainActivity.java I make a new object of this CustomList, but I'm using:
List<CustomObj> list = new CustomList(); (1)
and NOT:
CustomList list = new CustomList(); (2)
so far so good!
but when I try to access the function get(String searchName), there is no function I could use!
why? cause when I call it when creating the CustomList via (2) it'll totally work
its is because you are making List(Interface) has no any such method defined , you are making object of CustomList but reference type is List .so it will give you compile time errer if you force to call this method on List reference.This is an example of simple Polymorphism.
You can imagine a case where Mordern car extends Old age car and mordern car has GPS navigation system where as old doesn't in this case if you try to get the detail of navigation system by old car reference which doesn't know about GPS , you wont get anything.

Subsonic 3 - SimpleRepository Update = Object reference not set to an instance of an object

Seems fairly straight forward and simple, I am doing the following and getting an 'Object reference not set to an instance of an object.' error. It's a very simple update.
[AcceptVerbs(HttpVerbs.Post)][Authorize(Roles="admin")][ValidateInput(false)]
public ActionResult SaveContent(int id, string content)
{
var page = _repos.Single<Models.Page>(p=>p.PageID == id);
page.PageContent = content;
_repos.Update(page);
return RedirectToAction("Index",new { pagename=page.Name});
}
I can see in the debugger that I am actually getting my object and updating it with new values but the _repos.Update(page); chokes every time.
Anyone else having this issue?
This is a bug of SubSonic 3.0.0.3, you should go to http://github.com/subsonic/SubSonic-3.0/tree/master, get the latest source code and build the dll yourself.