Suppose i had this class:
abstract class DynamicallyAccessible{
operator [](String key){
throw 'DynamicallyAcessible [] operator is not implemented';
}
operator []=(String key,Object value){
throw 'DynamicallyAcessible []= operator is not implemented';
}
call(String methodName,List<Object> params){
throw 'DynamicallyAcessible call method is not implemented';
}
}
and this class which extends the above:
class Model extends DynamicallyAccessible{
String _a;
String get a => _a;
set a(v)=> _a=v;
String _b;
String get b => _b;
set b(v)=> _b=v;
int c;
dummyMethod(int a,int b){
return 6+a+b;
}
//this is to be generated by the transformer
//calls a getter or returns a value field by name
operator [](String key){
switch (key){
case 'a':return a;
case 'b':return b;
case 'c':return c;
default:throw 'no getter or field called $key';
}
}
//calls a setter or sets a field by name
operator []=(String key,Object value){
switch (key){
case 'a':a=value;return;
case 'b':b=value;return;
case 'c':c=value;return;
default:throw 'no setter or field called $key';
}
}
//calls a method by name
call(String key,List<Object> params){
switch(key){
case 'dummyMethod':return dummyMethod(params[0],params[1]);
default : throw 'no method called $key';
}
}
}
i implement the methods manually which is a waste of time, my question is does a transformer that does something similar exist or i have to write one from scratch, if not any suggestions to make this better?
the reason is to avoid using mirrors with dart2js
Here is an example of a transformer that use the analyzer package to find the classes that extends DynamicallyAccessible and inject the code for the operator[].
import 'package:barback/barback.dart';
import 'package:analyzer/analyzer.dart';
class DynamicallyAccessibleTransformer extends Transformer {
DynamicallyAccessibleTransformer.asPlugin();
get allowedExtensions => '.dart';
apply(Transform transform) async {
var content = await transform.readInputAsString(transform.primaryInput.id);
var newContent = _transformDartFile(content);
transform.addOutput(new Asset.fromString(transform.primaryInput.id, newContent));
}
String _transformDartFile(String content) {
CompilationUnit unit = parseCompilationUnit(content);
String newContent = content;
for (ClassDeclaration declaration in unit.declarations.reversed.where((d) => d is ClassDeclaration)) {
if (_isDynamicallyAccessible(declaration)) {
String sourceToInject = _createSourceToInject(declaration);
String before = content.substring(0, declaration.endToken.offset);
String after = content.substring(declaration.endToken.offset);
newContent = before + "\n$sourceToInject\n" + after;
}
}
return newContent;
}
/// TODO: this is a fragile approach as we only check for the class name
/// and not the library from where it comes. We probably should resolve
/// the Element and check the library.
_isDynamicallyAccessible(ClassDeclaration declaration) {
ExtendsClause extendsClause = declaration.extendsClause;
if (extendsClause != null) {
return extendsClause.superclass.name.name == 'DynamicallyAccessible';
}
return false;
}
_createSourceToInject(ClassDeclaration declaration) {
//TODO: do the same things for setters, methods and variable declaration.
String getterCases = declaration.members
.where((member) => member is MethodDeclaration && member.isGetter)
.map((MethodDeclaration getter) => getter.name.name)
.map((String name) => " case '$name': return $name;")
.join('\n');
return '''
operator [](String key) {
switch (key) {
$getterCases
default:throw 'no getter called \$key';
}
}
''';
}
}
Here is my version, also supports positional and named arguments for calling methods haven't tested deeply but it works fine
//TODO:support multiple inheritance where the sub class gets access to the super class members
class DynamicTransformer extends Transformer {
DynamicTransformer.asPlugin();
String get allowedExtensions => ".dart";
Future apply(Transform transform) async{
var logger = new BuildLogger(transform);
var content = await transform.primaryInput.readAsString();
var sourceFile = new SourceFile(content);
var transaction = _transformCompilationUnit(content,sourceFile,logger);
var id = transform.primaryInput.id;
if(transaction.hasEdits){
var printer = transaction.commit();
var url = id.path.startsWith('lib/')
? 'package:${id.package}/${id.path.substring(4)}' : id.path;
printer.build(url);
transform.addOutput(new Asset.fromString(id,printer.text));
}
return logger.writeOutput();
}
Future<bool> isPrimary(id) {
return new Future.value(id.extension == '.dart');
}
TextEditTransaction _transformCompilationUnit(
String inputCode, SourceFile sourceFile, BuildLogger logger) {
var unit = parseCompilationUnit(inputCode, suppressErrors: true);
var editor = new TextEditTransaction(inputCode, sourceFile);
unit.declarations
.where((dec) => dec is ClassDeclaration &&
isSubClassOrHasMixinOf(dec, 'DynamicAccess'))
.forEach((classDec) {
_transformClass(classDec,editor,sourceFile,logger);
});
return editor;
}
void _transformClass(ClassDeclaration cls, TextEditTransaction editor,
SourceFile file, BuildLogger logger) {
//TODO:throw another exception for private fields
var readWriteFieldNames = getClassDeclarationFieldDeclarationNames(cls,public:true);
var readOnlyFieldNames = getClassDeclarationFieldDeclarationNames(cls,public:true,readOnly:true);
var getters = getClassDeclarationMethodDeclarationNames(cls,getter:true).union(readWriteFieldNames).union(readOnlyFieldNames);
var setters = getClassDeclarationMethodDeclarationNames(cls,setter:true).union(readWriteFieldNames);
var methods = getClassDeclarationMethodDeclarations(cls,normal:true);
var methodsString = _buildSquareBracketsOperatorGet(getters);
methodsString+=_buildSquareBracketsOperatorAssignment(setters,readOnlyFieldNames);
methodsString+=_buildCallMethod(methods);
editor.edit(cls.endToken.offset,cls.endToken.offset,'$methodsString');
}
//build [] operator method
String _buildSquareBracketsOperatorGet(Set<String> getters) {
var sb = new StringBuffer();
sb.writeln('operator [](String key){');
sb.writeln('switch (key){');
getters.forEach((getter) {
sb.writeln("case '$getter': return this.$getter;");
});
sb.writeln("default:throw 'no getter or field called \$key';");
sb.writeln('}}');
return sb.toString();
}
String _buildSquareBracketsOperatorAssignment(Set<String> setters,Set<String> readOnlyFields) {
var sb = new StringBuffer();
sb.writeln('operator []=(String key,Object value){');
sb.writeln('switch (key){');
setters.forEach((setter) {
sb.writeln("case '$setter':this.$setter=value;return;");
});
readOnlyFields.forEach((readOnlyField) {
sb.writeln("case '$readOnlyField':throw 'field \$key is read only';return;");
});
sb.writeln("default:throw 'no setter or field called \$key';");
sb.writeln('}}');
return sb.toString();
}
String _buildCallMethod(Set<MethodDeclaration> methods){
var sb = new StringBuffer();
sb.writeln('call(String key,{List<Object> required:null,List<Object> positional:null,Map<String,Object> named:null}){');
sb.writeln('switch (key){');
methods.forEach((md){
sb.writeln("case '${md.name.name}': return this.${buildMethodCallString(md)}");
});
sb.writeln("default:throw 'no setter or field called \$key';");
sb.writeln('}}');
return sb.toString();
}
}
some utility methods:
isSubClassOrHasMixinOf(ClassDeclaration classDec, String superClassOrMixinName) {
if(classDec.withClause!=null){
print(classDec.withClause.mixinTypes);
}
if ((classDec.extendsClause != null &&
classDec.extendsClause.superclass.name.name == superClassOrMixinName) ||
(classDec.withClause != null &&
classDec.withClause.mixinTypes.any((type)=>type.name.name==superClassOrMixinName))) {
return true;
}
return false;
}
Set<String> getClassDeclarationFieldDeclarationNames(ClassDeclaration cd,
{public: true, private: false, readOnly: false}) {
var fieldNames = new Set<String>();
cd.members.forEach((m) {
if (m is FieldDeclaration) {
var fd = m as FieldDeclaration;
if ((fd.fields.isFinal || fd.fields.isConst) && readOnly || (!readOnly && !fd.fields.isFinal && !fd.fields.isConst)) {
fd.fields.variables.forEach((variable) {
var fName = variable.name.name;
if ((Identifier.isPrivateName(fName) && private) || (!Identifier.isPrivateName(fName) && public)) {
fieldNames.add(fName);
}
});
}
}
});
return fieldNames;
}
Set<FieldDeclaration> getClassDeclarationFieldDeclarations(ClassDeclaration cd,
{public: true, private: false, readOnly: false}) {
var fieldsDeclarations = new Set<FieldDeclaration>();
cd.members.forEach((m) {
if (m is FieldDeclaration) {
var fd = m as FieldDeclaration;
if ((fd.fields.isFinal || fd.fields.isConst) && readOnly || (!readOnly && !fd.fields.isFinal && !fd.fields.isConst)) {
fd.fields.variables.forEach((variable) {
if ((Identifier.isPrivateName(variable.name.name) && private) || (!Identifier.isPrivateName(variable.name.name) && public)) {
fieldsDeclarations.add(fd);
}
});
}
}
});
return fieldsDeclarations;
}
String buildMethodCallString(MethodDeclaration md){
var sb = new StringBuffer();
sb.write('${md.name.name}(');
var requiredParams = getMethodFormalParameterDeclarations(md,required:true);
if(requiredParams.length>0){
for(int i=0;i<requiredParams.length;i++){
sb.write('required[$i],');
};
}
var positionalParams = getMethodFormalParameterDeclarations(md,positional:true);
if(positionalParams.length>0){
for(int i=0;i<positionalParams.length;i++){
sb.write('(positional==null || positional[$i]==null)?${positionalParams[i].childEntities.last}:positional[$i],');
};
}
var namedParams = getMethodFormalParameterDeclarations(md,named:true);
if(namedParams.length > 0){
for(int i=0;i<namedParams.length;i++){
sb.write("${namedParams[i].identifier.name}:(named==null || !named.containsKey('${namedParams[i].identifier}'))?${namedParams[i].childEntities.last}:named['${namedParams[i].identifier}'],");
};
}
sb.write(');');
return sb.toString().replaceAll(r',)',')');
}
Set<MethodDeclaration> getClassDeclarationMethodDeclarations(
ClassDeclaration cd, {public: true, private: false, getter: false,
setter: false, operator: false, normal: false}) {
var methodDeclarations = new Set<MethodDeclaration>();
cd.members.forEach((d) {
if (d is MethodDeclaration) {
var md = d as MethodDeclaration;
var mName = md.name.name;
if ((Identifier.isPrivateName(mName) && private) ||
(!Identifier.isPrivateName(mName) && public)) {
if (md.isSetter && setter) {
methodDeclarations.add(md);
} else if (md.isGetter && getter) {
methodDeclarations.add(md);
} else if (md.isOperator && operator) {
//to do warn if [] []= are already overloaded and terminate
return;
} else if (normal && !md.isOperator && !md.isGetter && !md.isSetter) {
methodDeclarations.add(md);
}
}
}
});
return methodDeclarations;
}
Set<String> getClassDeclarationMethodDeclarationNames(
ClassDeclaration cd, {public: true, private: false, getter: false,
setter: false, operator: false, normal: false}) {
var methodDeclarationNames = new Set<String>();
cd.members.forEach((d) {
if (d is MethodDeclaration) {
var md = d as MethodDeclaration;
var mName = md.name.name;
if ((Identifier.isPrivateName(mName) && private) ||
(!Identifier.isPrivateName(mName) && public)) {
if (md.isSetter && setter) {
methodDeclarationNames.add(mName);
} else if (md.isGetter && getter) {
methodDeclarationNames.add(mName);
} else if (md.isOperator && operator) {
//to do warn if [] []= are already overloaded and terminate
return;
} else if (normal && !md.isOperator && !md.isGetter && !md.isSetter) {
methodDeclarationNames.add(mName);
}
}
}
});
return methodDeclarationNames;
}
List<FormalParameter> getMethodFormalParameterDeclarations(MethodDeclaration md,
{required: false, positional: false, named: false}) {
var formalParameters = new List<FormalParameter>();
md.parameters.parameters.forEach((fp) {
if ((fp.kind == ParameterKind.REQUIRED && required) ||
(fp.kind == ParameterKind.POSITIONAL && positional) ||
(fp.kind == ParameterKind.NAMED && named)) {
formalParameters.add(fp);
}
});
return formalParameters;
}
example:
class Model extends Object with DynamicAccess{
String _a;
String get a => _a;
set a(v)=> _a=v;
String _b;
String get b => _b;
set b(v)=> _b=v;
final int c=9;
String _z = 'xx';
dummyMethod(int a,int b){
return 6+a+b;
}
dummyNoParams(){
return 0;
}
dummyMethodWithPositionalParams(int a,String d,[int x=4,y=6]){
return '${a+x+y} $d';
}
dummyMethodWithNamedParams(int x,int y,{int f:4,String g:'no'}){
return '${x+y+f} $g';
}
}
gives:
class Model extends Object with DynamicAccess {
String _a;
String get a => _a;
set a(v) => _a = v;
String _b;
String get b => _b;
set b(v) => _b = v;
final int c = 9;
String _z = 'xx';
dummyMethod(int a, int b) {
return 6 + a + b;
}
dummyNoParams() {
return 0;
}
dummyMethodWithPositionalParams(int a, String d, [int x = 4, y = 6]) {
return '${a+x+y} $d';
}
dummyMethodWithNamedParams(int x, int y, {int f: 4, String g: 'no'}) {
return '${x+y+f} $g';
}
operator [](String key) {
switch (key) {
case 'a':
return this.a;
case 'b':
return this.b;
case 'c':
return this.c;
default:
throw 'no getter or field called $key';
}
}
operator []=(String key, Object value) {
switch (key) {
case 'a':
this.a = value;
return;
case 'b':
this.b = value;
return;
case 'c':
throw 'field $key is read only';
return;
default:
throw 'no setter or field called $key';
}
}
call(String key, {List<Object> required: null, List<Object> positional: null,
Map<String, Object> named: null}) {
switch (key) {
case 'dummyMethod':
return this.dummyMethod(required[0], required[1]);
case 'dummyNoParams':
return this.dummyNoParams();
case 'dummyMethodWithPositionalParams':
return this.dummyMethodWithPositionalParams(required[0], required[1],
(positional == null || positional[0] == null) ? 4 : positional[0],
(positional == null || positional[1] == null) ? 6 : positional[1]);
case 'dummyMethodWithNamedParams':
return this.dummyMethodWithNamedParams(required[0], required[1],
f: (named == null || !named.containsKey('f')) ? 4 : named['f'],
g: (named == null || !named.containsKey('g')) ? 'no' : named['g']);
default:
throw 'no setter or field called $key';
}
}
}
Related
I am calling service using ConnectionRequest class and if i'm getting result in English i'm able to display it but if i'm getting response in Hindi at that time getting as question marks(?) instead of Hindi text. and i'm using Devanagari Font to show the hindi text. is there any solution for this?
here is the code for how we are requesting?
adding parameters using Map like below.
Map<String, Object> map = new HashMap<String, Object>();
map.add("Key","Value");
map.add("Key1","Value1");
etc..
then passing this map object to requestService method.
private static Map<String, Object> requestService(Map<String, Object> data) {
Connection connection = null;
Dialog progress = new InfiniteProgress().showInifiniteBlocking();
try {
connection = new Connection(data);
NetworkManager networkManager = NetworkManager.getInstance();
networkManager.addToQueueAndWait(connection);
networkManager.setTimeout(600000);
if(connection.getResponseData() == null) {
return null;
}
} finally {
progress.dispose();
}
JSONParser jp = new JSONParser();
try {
Map<String, Object> result = jp.parseJSON(new InputStreamReader(new ByteArrayInputStream(connection.getResponseData()), "UTF-8"));
return result;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
Connection Class:
private static class Connection extends ConnectionRequest {
private final static char escapeS[] = new char[] { '"', '\\', '/', '\b', '\f', '\n', '\r', '\t' };
private final static char escapeR[] = new char[] { '"', '\\', '/', 'b', 'f', 'n', 'r', 't' };
private Map<String, Object> data;
private Connection(Map<String, Object> data) {
this.data = data;
setFailSilently(true);
setPost(true);
setWriteRequest(true);
setContentType("application/json");
setUrl(serverUrl);
}
#Override
protected void buildRequestBody(OutputStream os) throws IOException {
String v = buildJSON(data);
if(shouldWriteUTFAsGetBytes()) {
os.write(v.getBytes("UTF-8"));
} else {
OutputStreamWriter w = new OutputStreamWriter(os, "UTF-8");
w.write(v);
}
}
private static String buildJSON(Map<String, Object> data) {
StringBuilder json = new StringBuilder();
buildJSON(data, json);
return json.toString();
}
#SuppressWarnings("unchecked")
private static void buildJSON(Map<String, Object> data, StringBuilder json) {
json.append('{');
boolean first = true;
Object value;
for(String key: data.keySet()) {
value = data.get(key);
if(value == null) {
continue;
}
if(first) {
first = false;
} else {
json.append(",");
}
json.append('"').append(key).append("\":");
if(value instanceof Map) {
buildJSON((Map<String, Object>) value, json);
} else if(value instanceof Collection) {
buildJSON((Collection<Map<String, Object>>)value, json);
} else {
if(value instanceof Long || value instanceof Integer || value instanceof Double
|| value instanceof Short || value instanceof Float) {
json.append(value);
} else if(value instanceof Boolean) {
json.append((Boolean)value ? "true" : "false");
} else {
json.append('"').append(escape(value)).append('"');
}
}
}
json.append('}');
}
private static void buildJSON(Collection<Map<String, Object>> data, StringBuilder json) {
json.append('[');
boolean first = true;
for(Map<String, Object> e: data) {
if(first) {
first = false;
} else {
json.append(",");
}
buildJSON(e, json);
}
json.append(']');
}
private static String escape(Object any) {
if(any == null) {
return "";
}
String s = any.toString();
if(s == null) {
return "";
}
for(int i = 0; i < escapeS.length; i++) {
s = replace(s, escapeS[i], escapeR[i]);
}
return s;
}
private static String replace(String s, char c, char r) {
int i = s.indexOf(c);
if(i < 0) {
return s;
}
return s.substring(0, i) + "\\" + r + replace(s.substring(i + 1), c, r);
}
}
please guide me to achieve this?
That means the result is encoded in a foreign language encoding and should be read using the correct hindi text encoding.
I have an MVC 5 web app which talks to my class library for db needs and the class library uses Entity Framework 6 for that.
Below are 2 methods from the class library.
Both of them are initiating a new context. How do I make 'em use only one context instead, without using class level variable?
Also, if these 2 methods were to save stuff, context.SaveChanges(), how can I wrap them both into one transaction, even if the save happens in different classes?
public int FindUnknownByName(string name, string language)
{
using (var context = new ScriptEntities())
{
int languageId = this.FindLanguage(language);
var script = context.scripts.Where(l => l.Name == name && l.Unknown == true && l.LanguageId == languageId).FirstOrDefault();
if (script != null)
{
return script.Id;
}
return 0;
}
}
public int FindLanguage(string language)
{
using (var context = new ScriptEntities())
{
var lang = context.languages.Where(l => l.Name == language).FirstOrDefault();
if (lang != null)
{
return lang.Id;
}
return 0;
}
}
Make the context a private class variable.
private ScriptEntities context = new ScriptEntities()
public int FindUnknownByName(string name, string language)
{
int languageId = this.FindLanguage(language);
var script = context.scripts.Where(l => l.Name == name && l.Unknown == true && l.LanguageId == languageId).FirstOrDefault();
if (script != null)
{
return script.Id;
}
return 0;
}
public int FindLanguage(string language)
{
var lang = context.languages.Where(l => l.Name == language).FirstOrDefault();
if (lang != null)
{
return lang.Id;
}
return 0;
}
Also implement IDisposable and dispose context.
You can use extension methods:
public int FindUnknownByName(this ScriptEntities context, string name, string language)
{
int languageId = context.FindLanguage(language);
var script = context.scripts.Where(l => l.Name == name && l.Unknown == true && l.LanguageId == languageId).FirstOrDefault();
if (script != null)
{
return script.Id;
}
return 0;.
}
public int FindLanguage(this ScriptEntities context, string language)
{
var lang = context.languages.Where(l => l.Name == language).FirstOrDefault();
if (lang != null)
{
return lang.Id;
}
return 0;
}
then:
using (var context = new ScriptEntities())
{
var language = context.FindUnknownByName('name', 'language')
}
I'm using uBlogsy WebForms 3.0.2 on Umbraco 6.1.5...
And the posts on the landing page are not showing up.
The function PostService.Instance.GetPosts is returning 0 posts, even though there are posts in the correct location.
I still get 0 posts when I try to substitute this:
var posts = PostService.Instance
.GetPosts(
IPublishedContentHelper.GetNode((int)Model.Id)
).ToIPublishedContent(true);
int postCount = posts.Count();
Would anyone know why the PostService isn't working? Or, what is going on?
I had same problem couple of times with Ublogsy. So I decided to write my own codes as below:
(Its a bit long)
// get tag, label, or author from query string
var tag = Request.QueryString["tag"] ?? "";
var label = Request.QueryString["label"] ?? "";
var author = Request.QueryString["author"] ?? "";
var searchTerm = Request.QueryString["search"] ?? "";
var commenter = Request.QueryString["commenter"] ?? "";
int page = int.TryParse(Request.QueryString["page"], out page) ? page : 1;
var year = Request.QueryString["year"] ?? "";
var month = Request.QueryString["month"] ?? "";
var day = Request.QueryString["day"] ?? "";
int postCount;
IEnumerable<IPublishedContent> posts = new BlockingCollection<IPublishedContent>();
var filterResults = this.FilterAgainstPosts(this.Model.Content, tag, label, author, searchTerm, commenter, year, month);
if (filterResults != null)
{
posts = Enumerable.Take(filterResults.Skip((page - 1) * itemsPerPage), itemsPerPage);
}
#RenderForLanding(posts)
And my FilterAgainstPosts method is as follow:
#functions
{
private IEnumerable<IPublishedContent> FilterAgainstPosts(IPublishedContent landing, string tag, string label, string author, string searchTerm, string commenter, string year, string month)
{
IEnumerable<IPublishedContent> filteredPosts = landing.DescendantsOrSelf("uBlogsyPost").Where(x => x.GetProperty("umbracoNaviHide").Value.ToString() != "1");
if (!String.IsNullOrEmpty(searchTerm))
{
filteredPosts = filteredPosts.ForEach(i => this.FilterAgainstTerm(i, searchTerm));
}
if (!String.IsNullOrEmpty(tag))
{
filteredPosts = filteredPosts.ForEach(i => this.FilterUponTag(i, i.GetProperty("uBlogsyPostTags").Value.ToString(), tag));
}
if (!String.IsNullOrEmpty(label))
{
filteredPosts = filteredPosts.ForEach(i => this.FilterUponLabel(i, i.GetProperty("uBlogsyPostLabels").Value.ToString(), label));
}
if (!String.IsNullOrEmpty(author))
{
filteredPosts = filteredPosts.ForEach(i => this.FilterUponAuthor(i, i.GetProperty("uBlogsyPostAuthor").Value.ToString(), author));
}
//
//TODO: Coomenter search needs to added
//
if (!string.IsNullOrEmpty(year))
{
filteredPosts = filteredPosts.ForEach(i => this.FilterUponYear(i, i.GetProperty("uBlogsyPostDate").Value.ToString(), year));
}
if (!string.IsNullOrEmpty(month))
{
filteredPosts = filteredPosts.ForEach(i => this.FilterUponMonth(i, i.GetProperty("uBlogsyPostDate").Value.ToString(), month));
}
return filteredPosts.WhereNotNull();
}
private IPublishedContent FilterUponMonth(IPublishedContent currentNode, string postDate, string month)
{
DateTime postedDate;
if (DateTime.TryParse(postDate, out postedDate) && postedDate.Month.ToString() == month) return currentNode;
return null;
}
private IPublishedContent FilterUponYear(IPublishedContent currentNode, string postDate, string year)
{
DateTime postedDate;
if (DateTime.TryParse(postDate, out postedDate) && postedDate.Year.ToString() == year) return currentNode;
return null;
}
private IPublishedContent FilterUponAuthor(IPublishedContent currentNode, string authorId, string author)
{
if (String.IsNullOrEmpty(authorId)) return null;
//Loads relevant node
int authorNodeId = -1;
if (!Int32.TryParse(authorId, out authorNodeId)) return null;
Node authorNode = new Node(authorNodeId);
//Trims the author name and search for given name
if (authorNode.GetProperty("uBlogsyAuthorName") != null && authorNode.GetProperty("uBlogsyAuthorName").Value.ToUpper().Trim().Contains(author.ToUpper())) return currentNode;
return null;
}
private Boolean FilterUponAuthor(string authorId, string author)
{
if (String.IsNullOrEmpty(authorId)) return false;
int authorNodeId = -1;
if (!Int32.TryParse(authorId, out authorNodeId)) return false;
Node authorNode = new Node(authorNodeId);
if (authorNode.GetProperty("uBlogsyAuthorName") != null && authorNode.GetProperty("uBlogsyAuthorName").Value.ToUpper().Trim().Contains(author.ToUpper())) return true;
return false;
}
private Boolean FilterUponCategories(string categoryIds, string category)
{
if (String.IsNullOrEmpty(categoryIds)) return false;
int categoryNodeID = -1;
foreach (string catID in categoryIds.Split(','))
{
if (!Int32.TryParse(catID, out categoryNodeID)) continue;
Node categoryNode = new Node(categoryNodeID);
if (categoryNode.GetProperty("uBlogsyLabelName") != null && categoryNode.GetProperty("uBlogsyLabelName").Value.ToUpper().Trim().Contains(category.ToUpper())) return true;
}
return false;
}
private Boolean FilterUponTags(string tagIds, string tag)
{
if (String.IsNullOrEmpty(tagIds)) return false;
int tagNodeID = -1;
foreach (string tagID in tagIds.Split(','))
{
if (!Int32.TryParse(tagID, out tagNodeID)) continue;
Node tagNode = new Node(tagNodeID);
if (tagNode.GetProperty("uTagsyTagName") != null && tagNode.GetProperty("uTagsyTagName").Value.ToUpper().Trim().Contains(tag.ToUpper())) return true;
}
return false;
}
private IPublishedContent FilterUponLabel(IPublishedContent currentNode, string nodeIDs, string label)
{
if (String.IsNullOrEmpty(nodeIDs)) return null;
foreach (string nodeId in nodeIDs.Split(','))
{
int labelNodeId = -1;
if (!Int32.TryParse(nodeId, out labelNodeId))
continue;
//Loads relevant node
Node labelNode = new Node(labelNodeId);
if (labelNode.GetProperty("uBlogsyLabelName") != null && labelNode.GetProperty("uBlogsyLabelName").Value.ToUpper().Trim().Contains(label.ToUpper())) return currentNode;
}
return null;
}
private IPublishedContent FilterAgainstTerm(IPublishedContent currentNode, string searchTerm)
{
if (String.IsNullOrEmpty(searchTerm)) return currentNode;
if (currentNode.GetProperty("uBlogsyContentTitle").Value.ToString().ToUpper().Contains(searchTerm.ToUpper()) ||
currentNode.GetProperty("uBlogsyContentSummary").Value.ToString().ToUpper().Contains(searchTerm.ToUpper()) ||
currentNode.GetProperty("uBlogsyContentBody").Value.ToString().ToUpper().Contains(searchTerm.ToUpper()) ||
currentNode.GetProperty("uBlogsySeoKeywords").Value.ToString().ToUpper().Contains(searchTerm.ToUpper()) ||
currentNode.GetProperty("uBlogsySeoDescription").Value.ToString().ToUpper().Contains(searchTerm.ToUpper()) ||
currentNode.GetProperty("uBlogsyNavigationTitle").Value.ToString().ToUpper().Contains(searchTerm.ToUpper()) ||
FilterUponAuthor(currentNode.GetProperty("uBlogsyPostAuthor").Value.ToString(), searchTerm.ToUpper()) ||
FilterUponCategories(currentNode.GetProperty("uBlogsyPostLabels").Value.ToString(), searchTerm.ToUpper()) ||
FilterUponTags(currentNode.GetProperty("uBlogsyPostTags").Value.ToString(), searchTerm.ToUpper())
)
return currentNode;
return null;
}
private IPublishedContent FilterUponTag(IPublishedContent currentNode, string nodeIDs, string tag)
{
if (String.IsNullOrEmpty(nodeIDs)) return null;
foreach (string nodeId in nodeIDs.Split(','))
{
int tagNodeId = -1;
if (!Int32.TryParse(nodeId, out tagNodeId))
continue;
// Loads relevant TagNode
Node tagNode = new Node(tagNodeId);
if (tagNode.GetProperty("uTagsyTagName") != null && tagNode.GetProperty("uTagsyTagName").Value.ToUpper().Contains(tag.ToUpper())) return currentNode;
}
return null;
}
}
I have two methods for a database entity which gets the translation for selected language if it has one, or the default language translation.
public string GetName(int? LanguageId, int? DefaultLanguageId)
{
string retval = "";
var textInSelectedLanguage = this.CategoryTexts.Where(w => w.LanguageId == LanguageId).SingleOrDefault();
if (textInSelectedLanguage == null)
{
retval = this.CategoryTexts.Where(w => w.LanguageId == DefaultLanguageId).SingleOrDefault().Name;
}
else
{
retval = textInSelectedLanguage.Name;
}
return retval;
}
public string GetDescription(int? LanguageId, int? DefaultLanguageId)
{
string retval = "";
var textInSelectedLanguage = this.CategoryTexts.Where(w => w.LanguageId == LanguageId).SingleOrDefault();
if (textInSelectedLanguage == null)
{
retval = this.CategoryTexts.Where(w => w.LanguageId == DefaultLanguageId).SingleOrDefault().Description;
}
else
{
retval = textInSelectedLanguage.Description;
}
return retval;
}
As you can see they are very similar. If I have more properties to translate, this won't be a good implementation. The behavior is similar for the other translations.
How can reduce this code to one method?
I tried to use reflection but I didn't had any results.
Later...
I reduced my code to one method which return me the an entity instance with all the properties in the selected language or default language:
public CategoryText GetTranslation(int? DesiredLanguageId, int? DefaultLanguageId)
{
CategoryText retval = null;
var textInSelectedLanguage = this.CategoryTexts.Where(w => w.LanguageId == DesiredLanguageId).SingleOrDefault();
if (textInSelectedLanguage == null)
{
retval = this.CategoryTexts.Where(w => w.LanguageId == DefaultLanguageId).SingleOrDefault();
}
else
{
retval = textInSelectedLanguage;
}
return retval;
}
I think this method can be easily made generic by trying to find a way to replace my CategoryTexts Dbset with any other DbSet database entity. How can I do this?
Assuming you have an appropriate base class you could write it:-
public T GetTranslation<T>(DbSet<T> set, int? DesiredLanguageId, int? DefaultLanguageId)
where T:SomeBaseClassThatHasPropertyLanguageId
{
return
set.SingleOrDefault(w => w.LanguageId == DesiredLanguageId) ??
set.SingleOrDefault(w => w.LanguageId == DefaultLanguageId);
}
I somehow solved this.
I have an Internationalization class which with the following method:
public static T GetDbEntityTranslation<T>(ITranslatable Entity)
{
return (T)Entity.GetTranslation<T>(GetDefaultLanguage().Id, GetChosenLanguage().Id);
}
The ITranslatable interface:
public interface ITranslatable
{
T GetTranslation<T>(int? DesiredLanguageId, int? DefaultLanguageId);
}
My category class:
public partial class Category : ITranslatable
{
private LSEntities db = new LSEntities();
public T GetTranslation<T>(int? DesiredLanguageId, int? DefaultLanguageId)
{
CategoryText retval = null;
retval = db.CategoryTexts.Where(w => w.LanguageId == DesiredLanguageId && w.CategoryId == this.Id).SingleOrDefault()
?? this.CategoryTexts.Where(w => w.LanguageId == DefaultLanguageId && w.CategoryId == this.Id).SingleOrDefault()
?? this.CategoryTexts.Where(w => w.CategoryId == this.Id).FirstOrDefault();
if (retval == null)
throw new Exception("No translation found for this object");
return (T)(object)retval;
}
}
The problem was that I need to get my translation based on my category ID which is stored in Category class. My translations are searched in CategoryTexts property.
I have the following helper method in a ViewModelBase class, which is inherited by other view Models:
public string GetEnumName<T>(Enum value)
{
Type enumType = typeof(T);
var enumValue = Enum.GetName(enumType, value);
MemberInfo member = enumType.GetMember(enumValue)[0];
var attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
var outString = ((DisplayAttribute)attrs[0]).Name;
if (((DisplayAttribute)attrs[0]).ResourceType != null)
{
outString = ((DisplayAttribute)attrs[0]).GetName();
}
return outString;
}
I then call this from the view like this:
<p>
#{var rel = Model.GetEnumDisplayName<Enums.wheteverEnum>(Model.wheteverEnum); }
#rel
</p>
Question is - can I work this method so I don't have to tell it the type of the enum? Basically I'd like todo this for all enums:
#Model.GetEnumDisplayName(Model.wheteverEnum)
No typeof, no T, no need to add a reference to the Enums namespace in the View...
Possible?
You can simply remove the type parameter and make it an extension method.
public static string DisplayName(this Enum value)
{
Type enumType = value.GetType();
var enumValue = Enum.GetName(enumType, value);
MemberInfo member = enumType.GetMember(enumValue)[0];
var attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
var outString = ((DisplayAttribute)attrs[0]).Name;
if (((DisplayAttribute)attrs[0]).ResourceType != null)
{
outString = ((DisplayAttribute)attrs[0]).GetName();
}
return outString;
}
#Model.wheteverEnum.DisplayName()
Could you not write this as an extension method? Something like...
public static class EnumExtensions
{
public static string ToDescription(this Enum e)
{
var attributes = (DisplayAttribute[])e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DisplayAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
}
}
Usage:
#Model.WhateverEnum.ToDescription();
Nice work #jrummell!
I've added a small tweak below which captures the scenario where an enum doesn't have an associated Display attribute (currently it throws an exception)
/// <summary>
/// Gets the DataAnnotation DisplayName attribute for a given enum (for displaying enums values nicely to users)
/// </summary>
/// <param name="value">Enum value to get display for</param>
/// <returns>Pretty version of enum (if there is one)</returns>
/// <remarks>
/// Inspired by :
/// http://stackoverflow.com/questions/9328972/mvc-net-get-enum-display-name-in-view-without-having-to-refer-to-enum-type-in-vi
/// </remarks>
public static string DisplayFor(this Enum value) {
Type enumType = value.GetType();
var enumValue = Enum.GetName(enumType, value);
MemberInfo member = enumType.GetMember(enumValue)[0];
string outString = "";
var attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
if (attrs.Any()) {
var displayAttr = ((DisplayAttribute)attrs[0]);
outString = displayAttr.Name;
if (displayAttr.ResourceType != null) {
outString = displayAttr.GetName();
}
} else {
outString = value.ToString();
}
return outString;
}
The answer of #jrummell in VB.NET for the few of us...
Module ModuleExtension
<Extension()>
Public Function DisplayName(ByVal value As System.Enum) As String
Dim enumType As Type = value.GetType()
Dim enumValue = System.Enum.GetName(enumType, value)
Dim member As MemberInfo = enumType.GetMember(enumValue)(0)
Dim attrs = member.GetCustomAttributes(GetType(DisplayAttribute), False)
Dim outString = CType(attrs(0), DisplayAttribute).Name
If (CType(attrs(0), DisplayAttribute).ResourceType IsNot Nothing) Then
outString = CType(attrs(0), DisplayAttribute).GetName()
End If
Return outString
End Function
End Module
for anyone who might reach to this question, I found this a lot easier than any thing else:
https://www.codeproject.com/articles/776908/dealing-with-enum-in-mvc
Just create a folder "DisplayTemplate" under "Views\Shared", and create an empty view (Name it "Enum") in the new folder "DisplayTemplate", and copy this code to it"
#model Enum
#if (EnumHelper.IsValidForEnumHelper(ViewData.ModelMetadata))
{
// Display Enum using same names (from [Display] attributes) as in editors
string displayName = null;
foreach (SelectListItem item in EnumHelper.GetSelectList(ViewData.ModelMetadata, (Enum)Model))
{
if (item.Selected)
{
displayName = item.Text ?? item.Value;
}
}
// Handle the unexpected case that nothing is selected
if (String.IsNullOrEmpty(displayName))
{
if (Model == null)
{
displayName = String.Empty;
}
else
{
displayName = Model.ToString();
}
}
#Html.DisplayTextFor(model => displayName)
}
else
{
// This Enum type is not supported. Fall back to the text.
#Html.DisplayTextFor(model => model)
}
Here is an extension method that I've written to do just this... it has a little extra logic in it to parse Enum names and split by capital letters. You can override any name by using the Display Attribute
public static TAttribute GetAttribute<TAttribute>(this ICustomAttributeProvider parameterInfo) where TAttribute : Attribute
{
object[] attributes = parameterInfo.GetCustomAttributes(typeof(TAttribute), false);
return attributes.Length > 0 ? (TAttribute)attributes[0] : null;
}
public static bool HasAttribute<TAttribute>(this ICustomAttributeProvider parameterInfo) where TAttribute : Attribute
{
object[] attributes = parameterInfo.GetCustomAttributes(typeof(TAttribute), false);
return attributes.Length > 0 ? true : false;
}
public static string ToFriendlyEnum(this Enum type)
{
return type.GetType().HasAttribute<DescriptionAttribute>() ? type.GetType().GetAttribute<DescriptionAttribute>().Description : type.ToString().ToFriendlyEnum();
}
public static string ToFriendlyEnum(this string value)
{
char[] chars = value.ToCharArray();
string output = string.Empty;
for (int i = 0; i < chars.Length; i++)
{
if (i <= 0 || chars[i - 1].ToString() != chars[i - 1].ToString().ToUpper() && chars[i].ToString() != chars[i].ToString().ToLower())
{
output += " ";
}
output += chars[i];
}
return output.Trim();
}
The GetAttribute extension methods could be slightly overkill, but I use them elsewhere in my projects, so they got reused when I wrote my Enum extension. You could easily combine them back into the ToFriendlyEnum(this Enum type) method
The suggested sollutions does not worked for me with MVC3: so the helper below is good.:
public static string GetEnumDescription(this Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
string attr = field.GetCustomAttributesData()[0].NamedArguments[0].TypedValue.Value.ToString();
if (attr == null)
{
return name;
}
else
{
return attr;
}
}
}
return null;
}