'Cannot bind to the new value member. Parameter name: newDisplayMember'. - exception

I'm using C# in Visual Studio 2010. I have 2 comboboxes that pull data from the database. The code looks something like this:
cbo1.DisplayMember = "Name";
cbo1.ValueMember = "HROfficeLocationID";
cbo1.DataSource = offices;
cbo2.DisplayMember = "Name";
cbo2.ValueMember = "HROfficeLocationID";
cbo2.DataSource = offices;
I kept getting this exception: 'Cannot bind to the new value member. Parameter name: newDisplayMember'. I searched around and then reorganized the lines of code so that cbo.DataSource came before .DisplayMember and .ValueMember .It ended up looking something like this:
cbo1.DataSource = offices;
cbo1.DisplayMember = "Name";
cbo1.ValueMember = "HROfficeLocationID";
cbo2.DataSource = offices;
cbo2.DisplayMember = "Name";
cbo2.ValueMember = "HROfficeLocationID";
The exception went away. Just thought I'd share.

I had this occur when the internal class I was using had the varialbles as "internal". Changed them to "public" and it worked fine.

Specify as a Property, not as a variable in a class for example,
public class projectData
{
public string ProjName { get; set; }
public string ProjId { get; set; }
}
List<projectData> projects = getProjects();
lBoxFDTProjects.DataSource = projects;
lBoxFDTProjects.ValueMember = "ProjId";
lBoxFDTProjects.DisplayMember = "ProjName";

Some property attributes also cause this error like the [Browsable(false)]

public class CmbStringItem
{
public CmbStringItem(string text, string val)
{
Text = text;
Value = val;
}
private string text;
public string Text
{
get {return text;}
set {text = value;}
}
private string val;
[System.ComponentModel.BrowsableAttribute(true)] // must use
public string Value
{
get {return val;}
set {val = value;}
}
public override string ToString()
{
return Text;
}
}
List<CmbStringItem> items = new List<CmbStringItem>();
items.Add(new CmbStringItem("Onula", "0"));
items.Add(new CmbStringItem("Jedna", "1"));
items.Add(new CmbStringItem("Dva", "2"));
items.Add(new CmbStringItem("Tri", "3"));
this.cmbSklad.DataSource = items;
this.cmbSklad.ValueMember = "Value";
this.cmbSklad.DisplayMember = "Text";
this.cmbSklad.SelectedIndex = 0;
// set Chombobox - Display vlaue
cmbSklad.SelectedValue = "1";

Related

Using Newtonsoft JsonConverter to Encrypt JSON object

I'm developing a project that will require me to include credentials for things like an SMTP server. I'd like to store this information along with the complete details of the endpoint in an embedded JSON file, but I would like to have that information encrypted and then let my application decrypt it when it needs to establish a connection and log in. The JSON structure looks something like this:
{
"Endpoints" : [
{
"Endpoint" : {
"Host": "smtp.mydomain.tld",
"Port": 587,
"Username": "user#mydomain.tld",
"Password": "mYp#s$w0?d"
}
}
]
}
While what I'd really like to have actually stored in the file would look something like this:
{
"Endpoints" : [
{
"Endpoint" : "<BASE64_ENCODED_STRING>"
}
]
}
Using Newtonsoft's Json.NET, I've built the class object/properties to desriealize this structure:
<JsonProperty("Endpoints")>
Public Property Endpoints As List(Of EndpointContainer) = Nothing
Public Class EndpointContainer
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private Const EncryptedPrefix As String = "myappcipher:"
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
<JsonProperty("Endpoint")> <JsonConverter(GetType(EndpointProtector))>
Public Property Endpoint As Endpoint = Nothing
End Class
And I've built the inherited JsonConverter class ("EndpointProtector") like this:
Public Class EndpointProtector
Inherits JsonConverter
Public Sub New()
Using SHAEncryption = New SHA256Managed()
_EncryptionKey = SHAEncryption.ComputeHash(Encoding.UTF8.GetBytes(TestEncryptionKey))
End Using
End Sub
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
Dim clearText As String = JsonConvert.SerializeObject(value)
If clearText Is Nothing Then
Throw New ArgumentNullException(NameOf(clearText))
End If
writer.WriteValue(EncryptEndpoint(clearText))
End Sub
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
Dim DecryptString As String = TryCast(reader.Value, String)
If String.IsNullOrEmpty(DecryptString) Then
Return reader.Value
ElseIf Not DecryptString.StartsWith(EncryptedPrefix, StringComparison.OrdinalIgnoreCase) Then
Return DecryptString
Else
Return DecryptEndpoint(DecryptString)
End If
End Function
Public Overrides Function CanConvert(objectType As Type) As Boolean
Throw New NotImplementedException()
End Function
End Class
Currently I have the JSON file itself with the full object definition (as in the first code block). When my application reads that JSON, it correctly moves to the overridden ReadJson() method I have, but the reader.Value is null (Nothing), so it never actually gets to the DecryptEndpoint() method. Of course, that means there's nothing to encrypt, so the application won't even step into the WriteJson() method.
I've tried a couple of variations, including making the Endpoint property into a private variable with a generic Object type, and then having a separate public property with the <JsonIgnore> decoration to "read" from that, but nothing seems to get me where I need to be. I'm sure I'm overlooking something here, but I can't seem to figure out why it's not getting anything at all.
I looked at a few other SO questions like Encrypt and JSON Serialize an object, but I've still not yet been able to figure out quite where I've gone wrong here.
NOTE: I intentionally didn't include the code for the EncryptEndpoint() or DecryptEndpoint() methods here simply because the code is never making it that far in the process. If you feel it's needed to fully answer the question, please let me know.
this is a linqpad example of working encrypt/decrypt base on JsonAttribute
void Main()
{
string str = "";
var t = new Test() { encName = "some long text some long text some long text", Name = "test" };
JsonSerializerSettings theJsonSerializerSettings = new JsonSerializerSettings();
theJsonSerializerSettings.TypeNameHandling = TypeNameHandling.None;
str = JsonConvert.SerializeObject(t, theJsonSerializerSettings).Dump();
JsonConvert.DeserializeObject<Test>(str, theJsonSerializerSettings).Dump();
}
public class Test
{
[JsonConverter(typeof(EncryptingJsonConverter))]
public string encName { get; set; }
public string Name { get; set; }
}
/// <summary>[JsonConverter(typeof(EncryptingJsonConverter), string 32byte array)]</summary>
public class EncryptingJsonConverter : JsonConverter
{
private readonly byte[] _encryptionKeyBytes;
private readonly string _encryptionKeyString;
///<summary>Key must be 32char length</summary>
public EncryptingJsonConverter()
{
string encryptionKey = "E546C8DF278CD5931069B522E695D4F2"; //get from config
if (string.IsNullOrEmpty(encryptionKey))
throw new ArgumentNullException(nameof(encryptionKey));
_encryptionKeyString = encryptionKey;
_encryptionKeyBytes = Convert.FromBase64String(encryptionKey);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var stringValue = (string)value;
if (string.IsNullOrEmpty(stringValue))
{
writer.WriteNull();
return;
}
//string enc = stringValue.Encrypt(_encryptionKeyString);
string enc = Crypto.Encrypt(stringValue, _encryptionKeyBytes);
writer.WriteValue(enc);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = reader.Value as string;
if (string.IsNullOrEmpty(value))
return reader.Value;
try
{
//return value.Decrypt(_encryptionKeyString);
return Crypto.Decrypt(value, _encryptionKeyBytes);
}
catch
{
return string.Empty;
}
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
}
public static class Crypto
{
public static string Encrypt(this string text, string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Key must have valid value.", nameof(key));
if (string.IsNullOrEmpty(text))
throw new ArgumentException("The text must have valid value.", nameof(text));
var buffer = Encoding.UTF8.GetBytes(text);
var hash = SHA512.Create();
var aesKey = new byte[24];
Buffer.BlockCopy(hash.ComputeHash(Encoding.UTF8.GetBytes(key)), 0, aesKey, 0, 24);
using (var aes = Aes.Create())
{
if (aes == null)
throw new ArgumentException("Parameter must not be null.", nameof(aes));
aes.Key = aesKey;
using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
using (var resultStream = new MemoryStream())
{
using (var aesStream = new CryptoStream(resultStream, encryptor, CryptoStreamMode.Write))
using (var plainStream = new MemoryStream(buffer))
{
plainStream.CopyTo(aesStream);
}
var result = resultStream.ToArray();
var combined = new byte[aes.IV.Length + result.Length];
Array.ConstrainedCopy(aes.IV, 0, combined, 0, aes.IV.Length);
Array.ConstrainedCopy(result, 0, combined, aes.IV.Length, result.Length);
return Convert.ToBase64String(combined);
}
}
}
public static string Decrypt(this string encryptedText, string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Key must have valid value.", nameof(key));
if (string.IsNullOrEmpty(encryptedText))
throw new ArgumentException("The encrypted text must have valid value.", nameof(encryptedText));
var combined = Convert.FromBase64String(encryptedText);
var buffer = new byte[combined.Length];
var hash = new SHA512CryptoServiceProvider();
var aesKey = new byte[24];
Buffer.BlockCopy(hash.ComputeHash(Encoding.UTF8.GetBytes(key)), 0, aesKey, 0, 24);
using (var aes = Aes.Create())
{
if (aes == null)
throw new ArgumentException("Parameter must not be null.", nameof(aes));
aes.Key = aesKey;
var iv = new byte[aes.IV.Length];
var ciphertext = new byte[buffer.Length - iv.Length];
Array.ConstrainedCopy(combined, 0, iv, 0, iv.Length);
Array.ConstrainedCopy(combined, iv.Length, ciphertext, 0, ciphertext.Length);
aes.IV = iv;
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
using (var resultStream = new MemoryStream())
{
using (var aesStream = new CryptoStream(resultStream, decryptor, CryptoStreamMode.Write))
using (var plainStream = new MemoryStream(ciphertext))
{
plainStream.CopyTo(aesStream);
}
return Encoding.UTF8.GetString(resultStream.ToArray());
}
}
}
public static string Encrypt(string text, byte[] key)
{
//string keyString = "encrypt123456789";
//var key = Encoding.UTF8.GetBytes(keyString);//16 bit or 32 bit key string
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
var iv = aesAlg.IV;
var decryptedContent = msEncrypt.ToArray();
var result = new byte[iv.Length + decryptedContent.Length];
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);
return Convert.ToBase64String(result);
}
}
}
}
public static string Decrypt(string cipherText, byte[] key)
{
var fullCipher = Convert.FromBase64String(cipherText);
var iv = new byte[16];
var cipher = new byte[fullCipher.Length - iv.Length];//new byte[16];
Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, cipher.Length);
//var key = Encoding.UTF8.GetBytes(keyString);//same key string
using (var aesAlg = Aes.Create())
{
using (var decryptor = aesAlg.CreateDecryptor(key, iv))
{
string result;
using (var msDecrypt = new MemoryStream(cipher))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
return result;
}
}
}
}
to activate encryption just add a tag
[JsonConverter(typeof(EncryptingJsonConverter))]

.NET 6 - Change Json Property Casing

How can I change the casing of the property names of a json without performing model binding?
JsonElement serialization ignores PropertyNaming JsonSerializer options as is also confirmed here: https://github.com/dotnet/runtime/issues/61843
The suggested use of JsonNode/JsonObject results in the same behavior.
Any hints how I can accomplish this?
As example I want to change this:
{
"MyPoperty" : 5,
"MyComplexProperty" : {
"MyOtherProperty": "value",
"MyThirdProperty": true
}
}
to this:
{
"myPoperty" : 5,
"myComplexProperty" : {
"myOtherProperty": "value",
"myThirdProperty": true
}
}
Cheers.
I think you try to use Newtonsoft json
class Person
{
public string UserName { get; set; }
public int Age { get; set; }
}
coding
static void Main(string[] args)
{
Person person = new Person();
person.UserName = "Bob";
person.Age = 20;
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
var json = JsonConvert.SerializeObject(person, serializerSettings);
Console.WriteLine(json);
}
output
{"userName":"Bob","age":20}
not depend on Newtonsoft json but in the case of multi-layer objects
var json = #"{""ShouldWindUpAsCamelCase"":""does it?""}";
var obj = JsonSerializer.Deserialize<Dictionary<string,string>>(json);
var dic = new Dictionary<string, string>();
foreach (var item in obj)
{
dic.Add(item.Key.FirstCharToLower(), item.Value);
}
var serialized = System.Text.Json.JsonSerializer.Serialize(dic);
Console.WriteLine(serialized);
FirstCharToLower() function
public static string FirstCharToLower(this string input)
{
if (String.IsNullOrEmpty(input))
return input;
string str = input.First().ToString().ToLower() + input.Substring(1);
return str;
}
#output
{"shouldWindUpAsCamelCase":"does it?"}

post request of HttpClient of angular is not sending the proper data to server

In my below code, request is holding data {widgetName: "widgetName", widgetCriteria: "Activities", followUpDate: "1591727400000", uid: "someId"}
let request = JSON.parse(JSON.stringify(Object.assign(this.registrationForm.value, ...req)));
delete request.widgetFIlterOptions;
let uid = JSON.parse(window.localStorage.getItem("user")).uid;
request.uid = uid;
this.openWindow = false;
console.info("request-->", request);
this.contactService.addWidget(request).subscribe(res=> {
this.emService.updateWidgits();
})
Inside addWidget() function/method we are calling post request.
but after calling post request ResetController class should receive "followUpDate" with the other data. However in my case "followUpDate" is missing but I can see other data.
Can anyone help in this matter? What I am missing here? I am new to Angular.
addWidget(widget, data?) {
console.info("widget-->", widget); // here followUpDate is present
this.http.post(this.api.createWidget, widget).pipe(map(data => {
console.info("data-->", data); // this does not have the followUpDate.
let message = "Widget created successfully";
data['data'] = this.filterWidgets(data).length > 0 ? this.filterWidgets(data): alert("No data Available");
this.widgets.unshift(data);
this.toastr.success(message);
}),catchError(err => {
this.toastr.error(err.error);
return throwError(err);
}));
Below is my rest controller class
#RestController
public class DashboardController {
#Autowired
Service service;
#PostMapping(path = "createcriteria", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ApiOperation(value = "create the deal", response = Dashboard1.class)
public Dashboard1 saveCriteria(#RequestBody Dashboard1 dashboard1) {
System.out.println(dashboard1); // here "followUpDate" is missing
return service.saveCriteria(dashboard1);
}
}
Below is my Dashboard1 class
#Document(collection = "Dashboard1")
#JsonInclude(Include.NON_NULL)
public class Dashboard1 {
#Id
#ApiModelProperty(notes = "The database generated product ID")
private String id;
#Field(value = "widgetname")
private String WidgetName = null;
#Field(value = "widgetcriteria")
private String WidgetCriteria = null;
#Field(value = "uid")
private String uid = null;
#Field(value = "activitytype")
private String activityType = null;
#Field(value = "contactname")
private String contactName = null;
#Field(value = "updateby")
private String updateBy = null;
#Field(value = "followUpDate")
private String followUpDate = null;
// below all the getters, setters and toString() methods present
}
You dont need to JSON.stringfy the object. You just need to certify that the attribute names on json are the same of your class on spring, and just sed the pure object without the stringfy.
I found the issue in my code. Issue was in getters and setters. In my code field name and getter and setter name was different. Field name was followUpDate but the getter and setter name was getFallowUpDate() and setFallowUpDate(String)

Room returns incorrect initialized object from generated query

I have three tables, one containing Cards, one containing CardDecks and third one implementing a many-to-many relation between the former two and additionally containg a symbol for every relation entry.
My task is to get three columns from the card-table and the symbol from the relation-table and save it in a data Object specifically designed for handling those inputs, the codition being, that all entries match the given deckId. Or in (hopefully correct) sql-language:
#Query("SELECT R.symbol, C.title, C.type, C.source " +
"FROM card_table C JOIN cards_to_card_deck R ON C.id = R.card_id"+
"WHERE R.card_deck_id = :cardDeckId")
LiveData<List<CardWithSymbol>> getCardsWithSymbolInCardDeckById(long cardDeckId);
But the room implementation class generates:
#Override
public LiveData<List<CardWithSymbol>> getCardsWithSymbolInCardDeckById(long
cardDeckId) {
final String _sql = "SELECT R.symbol, C.title, C.typ, C.source FROM
cards_to_card_deck R INNER JOIN card_table C ON R.card_id = C.id WHERE
R.card_deck_id = ?";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
int _argIndex = 1;
_statement.bindLong(_argIndex, cardDeckId);
return new ComputableLiveData<List<CardWithSymbol>>() {
private Observer _observer;
#Override
protected List<CardWithSymbol> compute() {
if (_observer == null) {
_observer = new Observer("cards_to_card_deck","card_table") {
#Override
public void onInvalidated(#NonNull Set<String> tables) {
invalidate();
}
};
__db.getInvalidationTracker().addWeakObserver(_observer);
}
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfSymbol = _cursor.getColumnIndexOrThrow("symbol");
final List<CardWithSymbol> _result = new ArrayList<CardWithSymbol>(_cursor.getCount());
while(_cursor.moveToNext()) {
final CardWithSymbol _item;
final int _tmpSymbol;
_tmpSymbol = _cursor.getInt(_cursorIndexOfSymbol);
_item = new CardWithSymbol(_tmpSymbol,null,null,null);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
#Override
protected void finalize() {
_statement.release();
}
}.getLiveData();
}
Where
_item = new CardWithSymbol(_tmpSymbol,null,null,null);
should return my fully initialized object.
The CardWithSymbol class is declared as follows:
public class CardWithSymbol {
public int symbol;
public String cardName;
public String cardType;
public String cardSource;
public CardWithSymbol(int symbol, String cardName, String cardType, String cardSource){
this.symbol = symbol;
this.cardName = cardName;
this.cardType = cardType;
this.cardSource = cardSource;
}
And the types of the columns returned by the query are:
int symbol, String title, String type, String source
I already went through some debugging and the rest of the application works just fine. I can even read the symbol from the objects return by the query, but as mentioned above for some reason room ignores the other three parameters and just defaults them to null in the query-implementation.
So after some trial and error and reading through the dao-documentation once again i found my error:
When creating a class for handling subsets of columns in room, it is important to tell room which variable coresponds to which columns via #ColumnInfo(name = "name of the column goes here")-annotation.
So changing my CardWithSymbol class as follows solved the issue for me:
import android.arch.persistence.room.ColumnInfo;
public class CardWithSymbol {
#ColumnInfo(name = "symbol")
public int symbol;
#ColumnInfo(name = "title")
public String cardName;
#ColumnInfo(name = "type")
public String cardType;
#ColumnInfo(name = "source")
public String cardSource;
public CardWithSymbol(int symbol, String cardName, String cardType, String cardSource){
this.symbol = symbol;
this.cardName = cardName;
this.cardType = cardType;
this.cardSource = cardSource;
}
}

How does Asp.net Core renders a view

How does MVC 6 renders a view. What's the actual method in Razor ViewEngine that generates the html output? Also if possible please explain the process of rendering a view.
May be you could point me to a file on mvc source on github. thanks!
Here is a complete solution of what you are looking for. I used dependency injection to get the HtmlHelper in the controller. You can inject your own helper if you want too.
using Microsoft.AspNet.Html.Abstractions;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.WebEncoders;
using System.ComponentModel.DataAnnotations;
using System;
public class MyController : Controller
{
private readonly IHtmlGenerator htmlGenerator;
ICompositeViewEngine viewEngine;
IModelMetadataProvider metadataProvider;
private readonly IHtmlHelper helper;
IHtmlEncoder htmlEncoder;
IUrlEncoder urlEncoder;
IJavaScriptStringEncoder javaScriptStringEncoder;
public MyController(IHtmlHelper helper, IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IHtmlEncoder htmlEncoder, IUrlEncoder urlEncoder, IJavaScriptStringEncoder javaScriptStringEncoder)
{
this.htmlGenerator = htmlGenerator;
this.viewEngine = viewEngine;
this.metadataProvider = metadataProvider;
this.htmlEncoder = htmlEncoder;
this.urlEncoder = urlEncoder;
this.javaScriptStringEncoder = javaScriptStringEncoder;
this.helper = helper;
}
[HttpGet]
public IActionResult MyHtmlGenerator()
{
MyViewModel temp = new MyViewModel();
var options = new HtmlHelperOptions();
options.ClientValidationEnabled = true;
ViewDataDictionary<MyViewModel> dic = new ViewDataDictionary<MyViewModel>(this.metadataProvider, new ModelStateDictionary());
ViewContext cc = new ViewContext(ActionContext, new FakeView(), dic, TempData, TextWriter.Null, options);
var type = typeof(MyViewModel);
var metadata = this.metadataProvider.GetMetadataForType(type);
ModelExplorer modelEx = new ModelExplorer(this.metadataProvider, metadata, temp);
ViewData["Description"] = "test desc";
ViewData["Id"] = 1;
this.ViewData = new ViewDataDictionary(this.metadataProvider, new ModelStateDictionary());
IHtmlHelper<MyViewModel> dd = new HtmlHelper<MyViewModel>(this.htmlGenerator, this.viewEngine, this.metadataProvider, this.htmlEncoder, this.urlEncoder, this.javaScriptStringEncoder);
((ICanHasViewContext)dd).Contextualize(cc);
dd.ViewContext.ViewData = this.ViewData;
var desc = GetString(dd.TextBoxFor(m => m.ID));
var ID = GetString(dd.TextBoxFor(m => m.Description));
// Do whatever you want with the ID and desc
return new ContentResult() { Content = ID + desc };
}
public static string GetString(IHtmlContent content)
{
var writer = new System.IO.StringWriter();
content.WriteTo(writer, new HtmlEncoder());
return writer.ToString();
}
}
public class MyViewModel : BaseAssetViewModel
{
// [RegularExpression(#"^-?\d{1,13}(\.\d{0,5})?$|^-?\.\d{1,5}$")]
[Required]
public int ID { get; set; }
[MinLength(2)]
public string Description { get; set; }
// Property with no validation
public string Other { get; set; }
}
public class FakeView : IView
{
string IView.Path
{
get
{
throw new NotImplementedException();
}
}
public Task RenderAsync(ViewContext viewContext)
{
throw new InvalidOperationException();
}
Task IView.RenderAsync(ViewContext context)
{
throw new NotImplementedException();
}
}
I don't know if this may be of help, may be you have to start to look at tag helpers:
https://github.com/DamianEdwards/TagHelperStarterWeb
they're working to a different way to create helpers that integrate in the page in a more natural way.