Overwrite Property in Partial Class (Create fallback Property)
Hello! First timer here, gonna keep it short as I can!
I'm trying to implement a second part of the partial class SeoControls in one of my projects, SeoControls is a composition with different metadata properties that I define in Backoffice.
What I'd like to do is, for example, if I don't have the Meta Description defined in backoffice in the SeoControls, it will fallback to another property of the same page, so for example my IntroContent property (Short Description).
I attempted to follow this thread, but was unable to get results, this below is the first generated property that I want to "overwrite" in my second Seocontrols file, so that I can manipulate the return and point towards another property if it's empty.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "8.9.1")]
[ImplementPropertyType("metaDescription")]
public string MetaDescription => GetMetaDescription(this);
/// <summary>Static getter for Meta Description</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "8.9.1")]
public static string GetMetaDescription(ISeocontrols that) => that.Value<string>("metaDescription");
This below is my attempt at "overwriting" the property in another partial class in the same namespace
public partial class Seocontrols
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "8.9.1")]
[ImplementPropertyType("metaDescription")]
public string MetaDescription
{
get
{
if (String.IsNullOrWhiteSpace(GetMetaDescription(this)))
{
var test = (string)this.Parent.GetProperty("introContent").Value();
if(String.IsNullOrWhiteSpace(test))
{
return test;
}
return "";
}
else
{
return GetMetaDescription(this);
}
}
}
}
I hope I've explained it well enough for you to understand, I'm currently a student thus I have very limited knowledge :)
Thanks in advance!
Edit:
I'm using AppData as the current models builder setup, and the issue is currently it complains of it being duplicate MetaDescription property as they are both inside each of the SeoControl classes.
If I remove it from the generated one it doesn't give any compilation errors, obviously it will be recreated when models are generated once again, making sure the errors come back.
If I rename the property to something else, for example: FindMetaDescription, I can't seem to reach that property in my view via @Model.GetProperty("findMetaDescription").
A partial class, is just a part of the class in another file. This means you cant "override" a property in the way that you propose, since it is the same a having two properties in the same file, with the same name.
What we (the company I work for) normally do, is to put the logic either into the view rendering that meta-tags, or in a controller that can expose the data via the rules you specify.
The closest to your original proposal is to create a property with another name, or create a GetMetaDescription() method in your partial class. You could also implement GetMetaDescription() as an extension method.
I'm not sure that qualifies as an answer to the question? Even creating a property with a different name in this scenario wouldn't result in the issue OP has being resolved.
It seems he even wrote:
If I rename the property to something else, for example: FindMetaDescription, I can't seem to reach that property in my view via @Model.GetProperty("findMetaDescription").
My first solution I tried for this issue is probably the same to what you do at your company, all of this was implement in a PartialView for MetaTags and then a service class to do all the logic: check if exist, if not use this etc, but I was told by my tutor that there's a better way to manipulate this within the modelsbuilder straight away and is best practice in Umbraco 8.
The closest to your original proposal is to create a property with another name, or create a GetMetaDescription() method in your partial class. You could also implement GetMetaDescription() as an extension method.
How would I go about doing as you describe? I tried adding an property with another name namely findMetaDescription and then tried to implement in the view @Model.findMetaDescription / GetProperty("FindMetaDescription") but was unable to get anything from those properties.
It seems you are trying to invoke the properties as if they are value on the published content. They are not, they are properties created in your code, and need to be called like Model.[Property], in this case @Model.FindMetaDescription() or @Model.MetaDescription depending on what you implement.
I tried that, this is the Seocontrols.extended that I have:
public partial class Seocontrols
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "8.9.1")]
[ImplementPropertyType("findMetaDescription")]
public string FindMetaDescription
{
get
{
if (String.IsNullOrWhiteSpace(GetMetaDescription(this)))
{
var test = (string)this.Parent.GetProperty("introContent").Value();
if(String.IsNullOrWhiteSpace(test))
{
return test;
}
return "";
}
else
{
return GetMetaDescription(this);
}
}
}
}
So here I take GetMetaDescription() from the original generated file and return that in a different property namely FindMetaDescription. In one of the views that have this "composition" (seocontrols.generated.cs) I tried using @Model.FindMetaDescription, @Model.FindMetaDescription() and @Model.FindMetaDescription and all of them return compilation error:
CS1061 'Country' does not contain a definition for 'FindMetaDescription' and no accessible extension method 'FindMetaDescription' in the specific page view. Country who inherits SeoControls.
This below happens inside my search page, when I try to post the results of the search and then show that property.
CS1061 'IPublishedContent' does not contain a definition for 'FindMetaDescription' and no accessible extension method 'FindMetaDescription'
If you'd like to see specifics on how the search is built it's following a tutorial from Paul Seal (stripped of extra code, just barebones):
var results = Umbraco.ContentQuery.Search(searchQuery, string.Empty);
results = results.Take(count);
if (resultCount > 0)
{
foreach (var result in results)
{
@result.Content.FindMetaDescription
}
}
Thanks again for putting in the time, really doing my head in this one :)
The objects your are working with are exposed as IPublishedContent. You are creating a new property on a different type.
Starting with Seocontrols:
You have implemented a property, named like a method. This only exists on the Seocontrols class. In order to use the property, you need to make sure your content inherits from Seocontrols, otherwise you get the error you mention:
CS1061 'IPublishedContent' does not contain a definition for 'FindMetaDescription' and no accessible extension method 'FindMetaDescription'
In the error message, you will also find another solution to this.
Normally you will never get content that it the type of your composition, Seocontrols, but rather something that implements the Seocontrols, as defined in ISeocontrols.
You could then create an extension method, to allow this:
public static class PublishedContentExentions{
public static string GetMetaDescription(this IPublishedContent content){
//find description
}
}
in the method, you can then check if the content implements ISeocontrols:
public static string GetMetaDescription(this IPublishedContent content){
if(content is ISeocontrols seocontrols){
return seocontrols.MetaDescription;
}
return null;
}
You can also add more checks, matching other types:
public static string GetMetaDescription(this IPublishedContent content){
if(content is ICategory category){
return category.CategoryDescription;
}
if(content is ISeocontrols seocontrols){
return seocontrols.MetaDescription;
}
return null;
}
I'm in a similar situation here where to be able to call the custom "FindMetaDescription" string that was just added I needed to extend the interface ISeoControls, like such:
This made reaching the property possible, but opened up new issues where I am now getting the following errors:
'CountryPage' does not implement interface member 'ISeoControls.FindMetaDescription'
'Search' does not implement interface member 'ISeoControls.FindMetaDescription'
Unfortunately there is no way to generate this new property in the generated models from umbraco as it will just overwrite this on build. Any suggestions? :p
haha indeed, but for the sake of broadening our knowledge a bit, let us say I want to do this without implementing extension methods (in the way you do in your example) I feel like it should be possible by just extending the partials from umbracos generated files.
You can, but you need just need to implement the interface as the error says. In your CountryPage class you need to create a FindMetaDescription property with a getter, and the same in Search class.
Also, when a member starts with "Find" it sounds like it is an action than can do something. Normally properties are just "read / write". Find sounds like a method :)
Ahh okay, makes more sense now that you say it tbh. I tried implementing directly into the generated and it actually worked (not being overwritten) but it jump straight into the generated GetMetaDescription() method, so extending the other classes would make more sense to make it point to the correct method.
public partial class CountryPage : IPublishedContent, ISeoControls
{
public string FindMetaDescription
{
get
{
SeoControls test = new SeoControls(this);
return test.FindMetaDescription;
}
}
}
and then in the SeoControls:
public partial class SeoControls : PublishedContentModel, ISeoControls
{
public string FindMetaDescription
{
get
{
if (String.IsNullOrWhiteSpace(GetMetaDescription(this)))
{
var test =
(string)this.AncestorOrSelf().GetProperty("ingress").Value();
if (test.Length > 0)
{
var finalIngress = test.Length <= 250 ? test : test.Substring(0,
250);
var pattern = @"\(.*?\)";
var final = Regex.Replace(finalIngress, pattern, " ");
var finalString = final + "...";
return finalString;
}
return "";
}
else
{
return GetMetaDescription(this);
}
}
}
}
Thanks for all the help along the way to this solution, much appreciated! :)
Overwrite Property in Partial Class (Create fallback Property)
Hello! First timer here, gonna keep it short as I can!
I'm trying to implement a second part of the partial class SeoControls in one of my projects, SeoControls is a composition with different metadata properties that I define in Backoffice.
What I'd like to do is, for example, if I don't have the Meta Description defined in backoffice in the SeoControls, it will fallback to another property of the same page, so for example my IntroContent property (Short Description).
https://our.umbraco.com/forum/using-umbraco-and-getting-started/81273-extend-modelsbuilder-generated-classes
I attempted to follow this thread, but was unable to get results, this below is the first generated property that I want to "overwrite" in my second Seocontrols file, so that I can manipulate the return and point towards another property if it's empty.
This below is my attempt at "overwriting" the property in another partial class in the same namespace
I hope I've explained it well enough for you to understand, I'm currently a student thus I have very limited knowledge :)
Thanks in advance!
Edit:
I'm using AppData as the current models builder setup, and the issue is currently it complains of it being duplicate MetaDescription property as they are both inside each of the SeoControl classes.
If I remove it from the generated one it doesn't give any compilation errors, obviously it will be recreated when models are generated once again, making sure the errors come back.
If I rename the property to something else, for example: FindMetaDescription, I can't seem to reach that property in my view via @Model.GetProperty("findMetaDescription").
Hi,
A partial class, is just a part of the class in another file. This means you cant "override" a property in the way that you propose, since it is the same a having two properties in the same file, with the same name.
What we (the company I work for) normally do, is to put the logic either into the view rendering that meta-tags, or in a controller that can expose the data via the rules you specify.
The closest to your original proposal is to create a property with another name, or create a GetMetaDescription() method in your partial class. You could also implement GetMetaDescription() as an extension method.
HTH :)
I'm not sure that qualifies as an answer to the question? Even creating a property with a different name in this scenario wouldn't result in the issue OP has being resolved. It seems he even wrote:
So renaming won't work.
I missed that part ;)
Hello thanks for such a quick reply!
My first solution I tried for this issue is probably the same to what you do at your company, all of this was implement in a PartialView for MetaTags and then a service class to do all the logic: check if exist, if not use this etc, but I was told by my tutor that there's a better way to manipulate this within the modelsbuilder straight away and is best practice in Umbraco 8.
How would I go about doing as you describe? I tried adding an property with another name namely findMetaDescription and then tried to implement in the view @Model.findMetaDescription / GetProperty("FindMetaDescription") but was unable to get anything from those properties.
Hi,
It seems you are trying to invoke the properties as if they are value on the published content. They are not, they are properties created in your code, and need to be called like
Model.[Property]
, in this case@Model.FindMetaDescription()
or@Model.MetaDescription
depending on what you implement.HTH :)
I tried that, this is the Seocontrols.extended that I have:
So here I take GetMetaDescription() from the original generated file and return that in a different property namely FindMetaDescription. In one of the views that have this "composition" (seocontrols.generated.cs) I tried using @Model.FindMetaDescription, @Model.FindMetaDescription() and @Model.FindMetaDescription and all of them return compilation error:
This below happens inside my search page, when I try to post the results of the search and then show that property.
If you'd like to see specifics on how the search is built it's following a tutorial from Paul Seal (stripped of extra code, just barebones):
Thanks again for putting in the time, really doing my head in this one :)
Hi,
The objects your are working with are exposed as IPublishedContent. You are creating a new property on a different type.
Starting with Seocontrols:
You have implemented a property, named like a method. This only exists on the Seocontrols class. In order to use the property, you need to make sure your content inherits from Seocontrols, otherwise you get the error you mention:
In the error message, you will also find another solution to this.
Normally you will never get content that it the type of your composition, Seocontrols, but rather something that implements the Seocontrols, as defined in ISeocontrols.
You could then create an extension method, to allow this:
in the method, you can then check if the content implements ISeocontrols:
You can also add more checks, matching other types:
HTH :)
Hi,
I'm in a similar situation here where to be able to call the custom "FindMetaDescription" string that was just added I needed to extend the interface ISeoControls, like such:
This made reaching the property possible, but opened up new issues where I am now getting the following errors:
Unfortunately there is no way to generate this new property in the generated models from umbraco as it will just overwrite this on build. Any suggestions? :p
This is why extension method where invented :)
haha indeed, but for the sake of broadening our knowledge a bit, let us say I want to do this without implementing extension methods (in the way you do in your example) I feel like it should be possible by just extending the partials from umbracos generated files.
You can, but you need just need to implement the interface as the error says. In your CountryPage class you need to create a FindMetaDescription property with a getter, and the same in Search class.
In the corresponding generated.cs ? I will try it out and see if I can get it working :)
no - in another file, that you create
https://our.umbraco.com/documentation/reference/templating/modelsbuilder/Understand-And-Extend
Also, when a member starts with "Find" it sounds like it is an action than can do something. Normally properties are just "read / write". Find sounds like a method :)
Ahh okay, makes more sense now that you say it tbh. I tried implementing directly into the generated and it actually worked (not being overwritten) but it jump straight into the generated GetMetaDescription() method, so extending the other classes would make more sense to make it point to the correct method.
Will update shortly :p
Heyo,
Finally solved it!
and then in the SeoControls:
Thanks for all the help along the way to this solution, much appreciated! :)
Sorry for late answer, Isaiah have the final solution to our common issue, thanks for pointing us in the right direction Sören Gregersen =)
is working on a reply...