How to set custom templateBase as base template - c#

I made custom template using TemplateBase. How to set my template as razor base template. I managed to do this using old api but than I had problem with caching. In new api caching seems much easier but I can't find any example of setting own template as base template.

In your start up routine or similar, add the following
var templateConfig = new TemplateServiceConfiguration
{
BaseTemplateType = typeof(YourCustomTemplateBase<>)
};
var service = RazorEngineService.Create(templateConfig);
Engine.Razor = service;
Add your template base should be created as
public abstract class YourCustomTemplateBase<T> : TemplateBase<T>
{
public string CustomString { get; set; }
}

Related

How to xunit / Moq test an internal setter within a model in ASP.NET Core

public class Details
{
public int Id { get; internal set; }
public string Name { get; set; }
}
I have a task where a setter in a model has an internal attribute and I have tried adding stuff like
[assembly: InternalsVisibleTo("sometestrepo")]
over the model class but to no avail. I googled for a couple of hours and I can't seem to find an answer. Is it even possible to xunit test it or mock and object so that it would allow to create an object with an Id. Otherwise how else am I supposed to fully test CRUD methods that are all based around ID parameter?
The solution is to make private members that you want to test internal.
then you can add InternalsVisibleTo attribute.
[assembly: InternalsVisibleTo("sometestrepo")]
if you're using Moq,You can use something like that:-
var mockAddress = new Mock<Details>();
mockAddress.SetupGet(p => p.Id).Returns(42);
mockAddress.SetupGet(p => p.Name).Returns("Whatever you want to match");
var mockAddressRepository = new Mock<IRepository<Details>>();
var addresses = new List<Details> { mockAddress.Object };
mockAddressRepository.Setup(p => p.GetEnumerator()).Returns(addresses.GetEnumerator());
var addressToMatch = mockAddressRepository.Object.FirstOrDefault(address => address.Id == 42);
Console.WriteLine(addressToMatch.Name);
Expected Output Is:-
Whatever you want to match
One solution that might work is to use a fake.
In your Test class create a fake Details class, inheriting from Details. Then you could new up the property.
public class FakeDetails : Details
{
public new int Id { get; set; }
}
You could use the fake in your test then to set the properties.
var fakeDetails = new FakeDetails();
fakeDetails.Id = 15;
fakeDetails.Name = "Some Name";

Add [ApiController] Attribute to the class

I have implemented the project of migrating Asp.Net WebApi into Asp.Net Core 3.1.I have started to learning the Rosyln parser. Using Rosyln, I have to change "ApiController" property into attribute in the class name.
Sample.cs
namespace TestFile.TestData.Target
{
public class SampleFile: ApiController
{
}
}
into
namespace TestFile.TestData.Target
{
[ApiController]
public class SampleFile: ControllerBase
{
}
}
I have followed the link :
Adding custom attributes to C# classes using Roslyn. but didn't understand.
Kindly suggest on alternative solution on how to do using Roslyn.
What are you trying to achvieve? You have successfully added [ApiController] there is no more extra steps. The link is about adding attribute via source generetor (code that writes code) if you are just trying to add attribute you don't need source generators.
Btw Roslyn is name of the c# compiler. Wich is used to creating your entire application, not a tool for adding attributes to a class :)
If you are trying to generate class via source generators maybe edit the question a little bit
Finally I got this,
Sample.cs:
private void AddCustomClassAttribute(string TargetClassFile, string CustomAttributeName)
{
var code = File.ReadAllText(TargetClassFile);
var updateClassFile = InsertClassAttribute(code, CustomAttributeName).GetAwaiter().GetResult();
if (!string.IsNullOrEmpty(updateClassFile))
File.WriteAllText(TargetClassFile, updateClassFile);
}
private async Task<string> InsertClassAttribute(string Code, string CustomAttributeName)
{
// Parse the code into a SyntaxTree.
var tree = CSharpSyntaxTree.ParseText(Code);
// Get the root CompilationUnitSyntax.
var root = await tree.GetRootAsync().ConfigureAwait(false) as CompilationUnitSyntax;
var findNamespace = root.Members.Single(m => m is NamespaceDeclarationSyntax) as NamespaceDeclarationSyntax;
// Get all class declarations inside the namespace.
var classDeclarations = findNamespace.Members.Where(m => m is ClassDeclarationSyntax);
// find the main class from the findNameSapce
var findRootClass = classDeclarations.First() as ClassDeclarationSyntax;
var addCustomAttribute = AttributeList(
SingletonSeparatedList(
Attribute(IdentifierName(CustomAttributeName)))
).NormalizeWhitespace();
// To check whether specific attribute is present in the class or not then only insert given attribute
if (findRootClass.BaseList?.Types.ToFullString().Trim() == CustomAttributeName)
{
var attributes = findRootClass.AttributeLists.Add(addCustomAttribute);
root = root.ReplaceNode(
findRootClass,
findRootClass.WithAttributeLists(attributes)).NormalizeWhitespace();
return root.ToFullString();
}
return null;
}

Override MVC Model Display Name Annotation with Custom Functionality

I have the following method where I read from a key-value XML file. I pass in a key and am returned a value where I used to display on my view.
public static class TextManager
{
public static string GetValue(string key)
{
string returnVal = null;
XmlSerializer serializer = new XmlSerializer(typeof(Entries));
string path = HttpContext.Current.Server.MapPath("/App_Data/text-key-value.xml");
if (File.Exists(path))
{
Entries entries = (Entries)serializer.Deserialize(File.OpenRead(path));
var entry = entries.Where(u => u.Key == key).FirstOrDefault();
if (entry != null)
{
returnVal = entry.Value;
}
}
return returnVal;
}
}
Basically I want to be able to use this method in my model class as a data-annotation that will pull directly from my site text file and set to the display name property.
For instance I want to replace
[Display(Name = "Reference Code")]
public string ReferenceCode { get; set; }
With this
[DisplaySiteText("ReferenceCodeKey")]
public string ReferenceCode { get; set; }
DisplaySiteText would pass the string reference "ReferenceCodeKey" to the GetValue method, file the reference in the file and then set the standard Display name attribute to whatever was in the file.
How do I create my own custom model annotation to do this, I've written custom validation annotations in the past by creating a class that inherits from ValidationAttribute, but I don't think that will work in this case.
You can inherit DisplayNameAttribute for this purpose
public class DisplaySiteTextAttribute : DisplayNameAttribute
{
private string _key;
public DisplaySiteTextAttribute(string key)
{
_key = key;
}
public override string DisplayName
{
get
{
return TextManager.GetValue(_key);
}
}
}
There are several options to customize model metadata:
Customize the way that framework provides metadata. (Create ModelMedatadaProvider)
Create new Metadata attributes. (Implement IMetadataAware)
Modify existing attributes. (Derive existing attributes.)
The 3rd option has been discussed in the other answer. Here in this post, I'll share first and second options.
Option 1 - Customize the way that framework provides metadata
You can change the logic of getting display text without changing the attribute.
In fact it's responsibility of ModelMetaDataProvider to get mete data for model, including display text for properties. So as an option, you can keep the Display attribute intact and instead, create a new model metadata provider and return property metadata from a different source.
To do so, you can create a new metadata provider by deriving from DataAnnotationsModelMetadataProvider. Then override GetMetadataForProperty and call base, to get metadata. Then change DisplayName based on your logic by reading from your text manager.
You also need to register the new metadata provider as ModelMetadataProviders.Current in App_Start.
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
public class MyCustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor,
Type containerType,
PropertyDescriptor propertyDescriptor)
{
var metadata = base.GetMetadataForProperty(modelAccessor,
containerType, propertyDescriptor);
var display = propertyDescriptor.Attributes
.OfType<DisplayAttribute>().FirstOrDefault();
if (display != null)
{
metadata.DisplayName = TextManager.GetValue(display.Name);
}
return metadata;
}
}
And then register it in Application_Start():
ModelMetadataProviders.Current = new MyCustomModelMetadataProvider();
For more information take a look at DataAnnotationsModelMetadataProvider.cs source code in ASP.NET MVC sources.
This approach is useful when you want to change the way that you provide metadata for model. For example when you want to load display name and description from an external file rather than resources, without changing existing attributes.
Option 2 - Create new Metadata attributes
Another standard solution for creating metadata-aware attributes is creating an attribute and implementing IMetadataAware interface. Then in implementation of OnMetadataCreated you can easily set properties of metadata.
This approach doesn't need to register a new meta data provider. This approach is supported by the default metadata provider and is useful for creating new metadata-aware attributes:
using System;
using System.Web.Mvc;
public class CustomMetadataAttribure : Attribute, IMetadataAware
{
public string Key { get; set; }
public CustomMetadataAttribure(string key) => this.Key = key;
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.DisplayName = TextManager.GetValue(this.Key);
}
}
This approach is useful when you want to extend metadata attributes and add a few more attributes. For example when you want to add some attributes to control rendering. You can set ModelMetadata properties or add some new values to its AdditionalValues dictionary.
Maybe your DisplaySiteText attribute could inherit from the Display attribute and set the name using your helper class. Something like this:
public class DisplaySiteTextAttribute : DisplayAttribute
{
public DisplaySiteTextAttribute(string key)
{
Name = TextManager.GetValue(key);
}
}

Load multiple bindings with Ninject

I am trying to load bindings in a class for a project. I am using 3rd party extensions for Caching and the class I need to load looks like below using c# and .net framework 472 .
public class CouchbaseCache : ICouchbaseCache, IDistributedCache
{
public CouchbaseCache(ICouchbaseCacheBucketProvider provider, IOptions<CouchbaseCacheOptions> options);
public IBucket Bucket { get; }
public CouchbaseCacheOptions Options { get; }
}
usually, If I have to load, I would use something like
Bind().To().InSingletonScope();
But how would I do it for the above class by giving the bucket info and Options as values while loading it? I could not get my head around it.
Also, ICouchbaseCachebucketProvider is an interface derived from INamedbucketProvider and derived class looks like
public interface INamedBucketProvider
{
string BucketName { get; }
IBucket GetBucket();
}
So far, I was able to get CouchbaseClientDefinition set up like this
Bind<ICouchbaseClientDefinition>().ToMethod(ctx =>
{
var options = new CouchbaseClientDefinition
{
Servers = new List<Uri>
{
new Uri("http://couchbase.com/")
}
};
return options;
}).InSingletonScope();
I need to give Uri for couchbase and also bucket name and the logic is all over the place. Any knowledge sharing will be greatly appreciated.
if the argument for the constructor of the CouchbaseCache is identical for the whole application life time then you can bind it with the use of binding with constructor arguments something like this where you are loading:
var options = new CouchbaseClientDefinition
{
Servers = new List<Uri>
{
new Uri("http://couchbase.com/")
}
};
var couchbaseCacheBucketProvider= new CouchbaseCacheBucketProvider
{
...
};
Bind<ICouchbaseClientDefinition().To<CouchbaseCache >()
.WithConstructorArgument(couchbaseCacheBucketProvider, options);
but you have to provide the couchbaseCacheBucketProvider.
if the arguments are different but they are limited for example if you have two version of the arguments you can use the named binding like this
var options1 = new CouchbaseClientDefinition
{
...
};
var options2 = new CouchbaseClientDefinition
{
...
};
var couchbaseCacheBucketProvider1= new CouchbaseCacheBucketProvider
{
...
};
var couchbaseCacheBucketProvider2= new CouchbaseCacheBucketProvider
{
...
};
Bind < ICouchbaseClientDefinition().To<CouchbaseCache>().WithConstructorArgument(couchbaseCacheBucketProvider, options1).Named("FirstBinding");
Bind < ICouchbaseClientDefinition().To<CouchbaseCache>().WithConstructorArgument(couchbaseCacheBucketProvider, options2).Named("SecondBinding");
However another Alternative is to use the FactoryPattern/Singleton to create your CouchbaseCache object. Then you need just to inject the Factory Class that you created and you can use the Factory Class to get the required CouchbaseCache object whenever it is required.

MobileServiceClient with different Model name than table name

Is there a way in Xamarin using MobileServiceClient to add an attribute to the class name to have a different table name?
i.e
this._client = new MobileServiceClient("myurl");
this._blogTable = _client.GetTable<Blog>();
But the table on the server is XCHX_Blogs
I would like to have my model class something like this
[TableName("XCHX_Blogs")]
public class Blog {
...
}
I cant seem to find a way to do this mapping in Xamarin forms (in the model).
In order to do exactly what you are asking you'd have to pull the Mobile Service Client SDK source into your app (instead of using the Nuget) so that you could use the internal MobileServiceTable<T> constructor directly:
this._blogTable = new MobileServiceTable<Blog>("XCHX_Blogs", this._client);
Alternatively you can use the non-generic MobileServiceTable, but then you'll have to handle the JSON de/serialization:
this._blogTable = _client.GetTable("XCHX_Blogs");
var blog = new Blog();
await this._blogTable.InsertAsync(JObject.FromObject(blog));
You can use DataContractAttribute or JsonContainerAttribute or DataTableAttribute
[DataContractAttribute(Name = "tableName")]
public class MyClass { ... }
IMobileServiceTable<MyClass> table = client.GetTable<MyClass>();
or
[JsonObjectAttribute(Title = "tableName")]
public class MyClass { ... }
IMobileServiceTable<MyClass> table = client.GetTable<MyClass>();
or
[DataTableAttribute("tableName")]
public class MyClass { ... }
IMobileServiceTable<MyClass> table = client.GetTable<MyClass>();
Personaly, I prefer the last solution because naming is coherent with type of objects.

Categories