I have a Visual Studio Project Wizard that attempts to configure a VC# project to override the FullPath property for selected files from the template.
The following code is used from within function
public void ProjectFinishedGenerating(Project project)
string path = "some file name";
project.ProjectItems.Item("some file").Properties.Item("FullPath").Value = path;
System.Reflection.TargetParameterCountException: Invalid number of parameters. (Exception from HRESULT: 0x8002000E (DISP_E_BADPARAMCOUNT))
at EnvDTE.Property.set_Value(Object lppvReturn)
I know that I have a valid ProjectItem object because I can display the original value.
I think the problem is that the FullPath property is read-only. You can figure this out by looking at the definition in MSDN - http://msdn.microsoft.com/en-us/library/vslangproj.fileproperties.fullpath.aspx - it only has a getter defined.
To call set_Value, you need be updating a property that has a public setter. According to the properties documented on the FileProperties interface, the only settable properties are:
BuildAction
CustomTool
CustomToolNamespace
FileName
SubType
Related
Say I have an object of my custom class, called AppSettings, which has various properties that hold both value types (integers, doubles, strings, etc.) and reference types (arrays, other custom objects, etc.). Some of these custom objects have their own custom objects, so the path down to some of the value type properties can go very deep.
For example:
<Serializable()>
Public Class AppSettings
Public Property windowHeight As Integer = 600
Public Property windowWidth As Integer = 800
Public Property defaultLengthUnit As Unit = Units.meters
Public Property defaultAngleUnit As Unit = Units.degrees
End Class
Where Unit class is defined as:
<Serializable()>
Public Class Unit
Public Property Name As String
Public Property Abbreviation As String
Public Property Scale As Double
End Class
And Units module is defined as:
Public Module Units
Public meters As New Unit With {
.Name = "Meters",
.Abbreviation = "m.",
.Scale = 1
}
Public degrees As New Unit With {
.Name = "Degrees",
.Abbreviation = "°",
.Scale = 1
}
End Module
Some other code might refer or bind to some of the reference type properties, or their internal properties. Now, let's say I provide a way for the user to save current state of AppSettings by serializing it into XML:
Public Sub SerializeAppSettings(ByVal filename As String)
Using sw As StreamWriter = New StreamWriter(filename)
Dim xmls As XmlSerializer = New XmlSerializer(GetType(AppSettings))
xmls.Serialize(sw, appSettings)
End Using
End Sub
and then load them back (by deserializing) at any time while running the application:
Public Function DeserializeAppSettings(ByVal filename As String) As AppSettings
If Not File.Exists(filename) Then Return Nothing
Using sr As StreamReader = New StreamReader(filename)
Dim xmls As XmlSerializer = New XmlSerializer(GetType(AppSettings))
Return TryCast(xmls.Deserialize(sr), AppSettings)
End Using
End Function
It is called like so:
AppSettings = DeserializeAppSettings(settingsFilePath)
The problem here is that all the references to AppSettings that other objects and bindings have, are now broken, because deserialization replaces the old instance of AppSettings with a completely new instance, and the references are not transferred to it.
It appears that this doesn't break references to value-type properties (like windowHeight, which is Integer), but it definitely breaks references to reference-type properties, like defaultLengthUnit. So for example, if some other object or WPF control is referring/binding to, say, AppSettings.defaultLengthUnit.scaleToBaseUnit, it doesn't work anymore.
I wonder, how can I fix this, so that deserialization would replace the old instance of AppSettings and transfer all the references from it to the new instance that it generated?
As I understand it, there are three ways to go about it:
Replace the old instance with an new one in the exact same memory allocation, with the same internal ID, which would probably be too hacky, and I'm not sure if at all possible.
Another way would be for the DeserializeAppSettings function to overwrite each property value of the current AppSettings instance, one by one, by the deserialized values. However, since some properties of AppSettings are objects, which have their own objects, which have their own objects (and so on), I would basically need to type out all the hierarchy tree in that DeserializeAppSettings function to get down to the value type properties. And every time I would need to add or remove any property in the AppSettings class (or in any class that is used in it's properties), I would also need to manually update the parsing code in DeserializeAppSettings function. This is seriously unmaintainable.
Lastly, it would probably be possible to automate this value replacement through reflection, but reflection is very slow, and generally discouraged if there is any other option.
I hope I am missing something obvious here. Any suggestions on how to transfer all the references to AppSettings when the old instance of it is replaced with a new one through deserialization?
EDIT: Updated the code to include all the relevant classes.
According to the documentation:
The runtime doesn’t look up localized strings for non-validation attributes. In the code above, “Email” (from [Display(Name = "Email")]) will not be localized.
I'm looking for a way to localize text in DisplayAttribute. Any suggestions to do it in a proper way(s)?
You can set the ResourceType on the DisplayAttribute which can be used to localize your text.
Add a resource .resx file to your project e.g. MyResources.resx, and add a resource for your field:
Then reference the name of the field and the MyResources type in your DisplayAttribute
[Display(Name = "RememberMe", ResourceType = typeof(MyResources))]
public bool RememberMe { get; set; }
The localized resource will be pulled through automatically (see the text box)
Having a Central location for all your localization whether in view or dataannotations is the best approach I can think of, and this how I got to work.
In Startup.cs file after you installed nuget packages for localization add the following code
services.AddMvc().AddViewLocalization().AddDataAnnotationsLocalization(options =>
options.DataAnnotationLocalizerProvider = (type, factory) => new StringLocalizer<Resources>(factory));
services.Configure<RequestLocalizationOptions>(options => {
var cultures = new[]
{
new CultureInfo("en"),
new CultureInfo("ar")
};
options.DefaultRequestCulture = new RequestCulture("en", "en");
options.SupportedCultures = cultures;
options.SupportedUICultures = cultures;
});
This way the DataAnnotationLocalizerProvider will be from the Resources.{culture}.rex -( The Resource file must have an access modifier of No code gen)- assuming that no resources will be needed for the default language, and to be able to access the resource file since no code will be generated and empty class with the same name must be created.
and in _ViewImports.cshtml file inject the following
#inject IHtmlLocalizer<Resources> Localizer
by doing this you now have a global variable Localizer to be used in any of the views for localization purposes.
you can find further information on Globalization and localization in ASP.NET Core
For those who struggle (#lucius, #vladislav) with error:
Cannot retrieve property 'Name' because localization failed. Type 'Xxxx.EmployeeResx' is not public or does not contain a public static string property with the name 'FirstName'.
It is caused by access modifier on .resx files which is by default set to Internal (in my case it was No code generation). Change it to public in Access Modifier dropdown in the resource file toolbar.
After that you should be able to see the properties from the resource type:
Also, consider not using special signs in field names as they are a basis for auto-generated C# property names. The field names are converted into C# friendly names and that is why you can end up with inconsistency between name of resource file field and name of auto-generated property. Best to avoid any hyphens - or dots . Underscores _ are fine. You can always look up how the auto-generated properties look like in resource_file_name.Designer.cs class under the related resource file.
Many thanks to Bala Murugan who wrote a good article concerning this topic on Code Digest.
Actually I found an simple solution for the followers. The display name in most of time is used in the label of an input field. So do this if you like:
<label asp-for="Email">#Localizer["Email"]</label>
of course, you can pass the property name by #Html.DisplayNameFor, but most of time, this one already works well.
I have just created a project which demonstrates localization including localization of Display attribute for class properties as well as enums.
The project can be found here https://github.com/feradz/ASPNetCoreLocalization/wiki
The Display attribute has to be localized using the approach prior to ASP.NET Core 1.0. Have a look at the DataAnnotations.resx file in the project.
The Name property of Display cannot contain empty spaces, and special characters.
[Display(Name = "NoSpacesAndSpecialChanractersHere", ResourceType = typeof(Resources.DataAnnotations))]
public string FirstName { get; set; }
ResourceType should be the fully qualified resource class name (i.e. including the name space).
So, i'm not sure what i'm doing wrong here but for some reason the callback function in TypeScript that i have doesn't have anything but _proto in the response's .data property whenever i set private properties in C# and new up an object that is filled with constructed properties. However, if the properties are public and i don't use a constructor then i can see the response's .data property is filled like i would expect it to be. Here is an example of what works:
public class ThisWorks{
public string MyProperty{get;set;}
}
Inside application layer:
ThisWorks example = new ThisWorks();
example.MyProperty = myReflectedProperty;
return example;
However, this does not work:
public class ThisDoesNotWork{
private string MyPrivateProperty {get;set;}
public ThisDoesNotWork(string myPrivateProperty){
MyPrivateProperty = myPrivateProperty;
}
}
What's causing this to happen? My TypeScript service has not changed but for some reason the data isn't coming across from the service call...Any help would be greatly appreciated!
I wrote a DLL in C# in VS2012:
namespace COMTest
{
public class MyClass
{
public int Fun()
{
return 3;
}
}
}
And then I set "Make Assembly COM Visible=True" and in the Build page, I set "Register COM for intercrop". Then create a new VB6 project, add a reference to the generated dll file but failed……Later tried tlb file succeeded but without intellisense after saying "a." (No "Fun" tip)
Dim a As MyClass
Set a = New MyClass
MsgBox (a.Fun())
So my questions are:
1) Why must I refer tlb file instead of dll file?
2) Why no intellisense?
Try placing a check mark in:
Tools->Options->Editor->Auto List Members
If that does not help, then to resolve this problem, define a public interface by using methods and properties that you want to expose in the TLB, and then implement the interface in the class. Also, add the ClassInterface (ClassInterfaceType.None) attribute to the class. As you develop the component, you can use this approach to avoid using the ComVisible(False) attribute.
You can have more details here
I have a very simple class called person.
public class Person{
[DataMember(Name="MyName")]
public string Name { get;set;}
}
If I try to serialize or de-serialize, everything works great. In the XML I can see a tag called "MyName" and in the object I see with the VS Intellisense a property called Name.
What I need now is to access, from the object, the serialized name of the property.
For example, I can do object.GetType().GetProperty("Name"); but if I try to do object.GetType().GetProperty("MyName"), the reflection says that the property does not exist. How I can read the serialized name of the property? Is there a way?
It seems that the only way is to access, using reflection, the attributes of the property in this way:
var att = myProperty.GetType().GetAttributes();
var attribute = property.GetCustomAttributes(false)[0] as DataMemberAttribute;
Console.WriteLine(attribute.Name);
This works on both, client and server, without the need of serialize and deserialize the object.