I am just beginning to use the WPFLocalizeExtension in a project. It works, but it has a serious impact on the startup performance of the app. It tries to load the resources for all possible languages, including many which we won't ever provide resources for. Normally that might happen without notice, but in this case we have a special folder structure for some of the loaded assemblies. Although the resource DLLs are still situated in language folders directly beneath the folder of the executable, but the app gets an AssemblyResolve event for every language.
Thanks for your help in advance.
We had the same problem and approached it by modifying the WPFLocalizeExtension source code.
When you have a look at the code, you will find a class called ResxLocalizationProviderBase. This class includes a method GetResourcemanager, which causes the massive amounts of AssemblyResolve events, because it tries to get the resource set of all cultures that ship with the .NET Framework (line 498):
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (var c in cultures)
{
...
}
We modified the code by creating a list of CultureInfo objects, that includes only languages, we'd like to provide resources for.
Related
I need to extract some resources from the MyForm.resx file in runtime. In particular, I need to access captions of controls, which are stored inside.
From what I know, resources are embedded into assembly during compilation. Knowing specific form I want access to (let it be MyForm) and specific name of the resource (like lbSth.Text), is there a way to access those resources in runtime?
There are two ways, depending on what is actually needed.
One may use System.Resources.ResourceManager class. Construct it by passing a Type of form or control, which resources you want to access. It automatically resolves satellite assemblies and provides access to resources related to a form. The downside is that it doesn't allow iterating through key/value pairs, only accessing a resource of known key, so you have to know them in advance (for instance, process resx files beforehand)
It turns out, that resources in binary form are kept as embedded resources in the assembly. However, translations are being kept in satellite assemblies. To access those, use eg. Assembly.GetExecutingAssembly().GetSatelliteAssembly(), however keep in mind, that resources in there will have different names. For instance, MyForm.resources in satellite assembly will be named, eg. MyForm.en.resources.
Afterwards, use resolvedAssembly.GetManifestResourceStream() to access embedded resource and then finally System.Resources.ResourceReader class to iterate through resources in that file.
I have a Silverlight solution that has multiple silverlight projects (Views) that all compile to their own .Xap file.
There is one "master" project that handles the dynamic downloading of the Xap files, which works pretty well.
But now I need to make sure that all the references are set to CopyLocal=false in all the View Projects. Only the "master" project can have CopyLocal=true.
This means that the Xap files generated by the Views stay rather small.
What I would like to do is check post or during the build process to see if any of the View projects have a reference with CopyLocal=true.
What would be a smart way of doing this? Using an external tool in the Post Build event? Or perhaps an addin for Visual Studio ? Or creating a macro in Visual Studio for this?
I have looked at using .extmap with assembly caching, but since you have to specify the assemblies in that, this does not solve my problem. I just need to know if there is a reference with the wrong setting and report that. Fixing it is not the question, that will still be done manually. It's just the notification I need.
Solution has 35 projects now, so dont want to check them all by hand every time.
I found a question similar to this one, but it lists msbuild as a possible solution. I would like to know if there is a way to do this using "code" (be it prebuilt in a tool/addin or otherwise)
I have chosen to go the Addin path. I created an addin that listens to : BuildEvents.OnBuildBegin
Whenever that event fires I create a list of all projects in the current solution. Doing a bit of recursive searching since there are also Solution folders that make life in DTE world a bit harder.
Then I loop through all the projects and cast them to a VSProject so I can loop through all the references.
Anytime I come accross a reference that is wrong, I create an ErrorTask where I set the Document property to the full solution path of the reference. To do this I Build the path for the project this reference is in, all the way up to the root of the solution.
The ErrorTask is then sent to an ErrorListHelper class I created, that handles the ErrorTasks and also performs navigation.
If I'm done with all the projects and I found any errors, I cancel the current build and show the Error List window, where my ErrorListHelper holds all the Reference Errors I created.
Whenever I want to navigate to the Reference in question, I activate the Solution Explorer window and get the root of it using an UIHierarchy.
Then I walk the path from the root on down, step by step, using the UIHierarchy to get to the UIHierarchyItems and expand them. Until I get to the deepest level (the reference) and I Select that.
Since I only need it for a certain solution and within that solution for certain projects (.Views.* and .ViewModels.*) I also have some checking for those in place during buildup of the Error List.
It works like a charm, already found 12 "wrong" References in 35 projects where I tought all were well.
I am using a different path now to do this. I have a base class that I can use to write unit tests that have access to the DTE2 object. This way I dont need an addin. This also works for Silverlight projects since the test class does not actually need access to the Silverlight projects, just being in the solution is enough to be able to iterate through the projects and check the references.
I am developing a commercial VB.net WPF application that needs user generated scripts for controlling the application to be shared between users. The best way that I have come across of accomplishing this so far without writing my own parser is using the Microsoft Script Control.
It would appear that both VBScripts and JScripts run through this control have access to wscript and as a result are too powerful to be shared between programmers and non-technical users for obvious security reasons.
I have considered trying to filter out dangerous scripts with some kind of regex parsing or something but that just seems far too risky and easy to circumvent.
So, is there some way of using this control but blocking its access to the system so that it could be used for controlling only the objects that I give it? If not, could someone recommend a better way of doing this?
I do not particularly mind what language the script would be in at this stage, although having multiple options would be nice.
EDIT: I am basing my conclusion that the control is too powerful for this on the fact that the following JScript code successfully launches notepad when called using the .AddCode and .Run methods of the control.
function test(){
var shell = new ActiveXObject("WScript.shell");
shell.run("notepad.exe", 1);
}
Thanks for all the help,
Sam.
If you just need to kill the ActiveXObject feature which is the entry point to the system, you can silently append some lines to the code you give to the Script Control, like this for example:
ActiveXObject = null; // add this silently
function test(){
var shell = new ActiveXObject("WScript.shell"); // this will now fail
shell.run("notepad.exe", 1);
}
Of course, if you still need to give some functions to your users, you will then need to propose some sort of an API, use the AddObject function (see How To Use the AddObject Method of the Script Control), and the user would use it like this:
ActiveXObject = null; // add this silently
function test(){
// this is a controlled method, because I have added a MyAPI named object
// using AddObject, and this object has a OpenNotepad method.
MyAPI.OpenNotepad();
}
PS: WScript is a, ActiveX Scripting host, so it's not accessible from the Script Control.
PS2: This hack does not work in every Script Control underlying languages. It works in JavaScript, but not in VBScript for example.
From your question, it doesn't look like you gave any consideration to any of the open-source script engines out there. I would suggest that those open-source libraries could solve your sandbox problem much more easily than the Microsoft Script Control.
The way I understand it, your requirements are:
Must be able to pass objects from your program into the scripting environment, so the script can use those objects to interact with the host app.
Must not be allowed to do unsafe things like access files, launch applications, create COM objects, etc.
Given those requirements, you have quite a few options.
The first thing that comes to mind is Jint, an open-source JavaScript interpreter written in .NET that you can embed in your app. You can pass .NET objects to the script. By default, the script can actually access any class in the .NET Framework, but the script is sandboxed by default (using .NET's built-in Code Access Security), so the script can't do anything unsafe. (For example, it could use things like StringBuilder or Regex, but it would get an exception if it tried to use FileStream.) If you want, you can disable the .NET access entirely, but even with it enabled, the default sandbox would probably suit your needs.
If for some reason Jint doesn't meet your requirements, some of the other open-source JavaScript-for-.NET engines I can think of off the top of my head are Jurassic, IronJS, and JavaScript .NET.
If it matters to you, Jint, Jurassic, and IronJS are all available through NuGet.
Normally, I put what I consider the constitutional root resources, such as brand colours/brushes, fonts and sizes down in the 'distrib' assembly.
The Distrib assembly|ies are designed to go out to 3rd party dev shops, so they have access our contracts, interfaces, and branding styles.
More complex resources are then built up and declared 'nearer' where they're used.
I've come along to an application that has grown organically, err, haphazardly. What's odd is that the modules use resources from the main app executable project, even though the modules don't reference the app.
I assume that because they're 'importing' all the resources into App.xaml, they're available to the psuedo-runtime designer context.
My question is
If this is how MS designed it to work, have I been doing it wrong all along by managing resources like I do a type system?
Thanks
Luke
** UPDATE **
So, it was pointed out to me that well organised resources are not the way to go in WPF due to a severe performance problem (much as I had found in a big SL4 app I worked on, but assumed it was an SL thing).
Assuming that managing resources in this highly organised way can still be done with a trick or two, and that modular systems often need to merge dictionaries, I began to look into using Christian Moser's SharedResourceDictionary solution, but I get a problem at design time only:
System.IO.Packaging.PackUriHelper
The URI prefix is not recognized.
at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
at System.Net.WebRequest.Create(Uri requestUri)
at MS.Internal.WpfWebRequestHelper.CreateRequest(Uri uri)
at System.Windows.ResourceDictionary.set_Source(Uri value)
at CompanyName.Presentation.SharedResourceDictionary.set_Source(Uri value)
It looks like it doesn't understand the pack Uris, which is odd since the SharedResourceDictionary just calls down to the original MS implementation in ResourceDictionary, and registering the pack URI scheme statically doesn't help either!! Grrr.
So I need to crack on and the second option is to smash everything into App.xaml and avoid merged dictionaries.
This means fewer controls/views, and setting up a design-time dictionary in my distributable library which I guess does the job of the app.xaml which they won't have access to.
I think that makes sense.
Interesting? Tell Microsoft
It may be for Silverlight, but I'm hoping the WPF folks might be listening, or at least it might fix one platform -- I've added an 'idea' to the UserVoice site that you can vote up.
http://dotnet.uservoice.com/forums/4325-silverlight-feature-suggestions/suggestions/2307678-fix-the-mergeddictionary-perf-problem
Yes, the App.xaml thing seems to be kind of how it's 'supposed' to work, although obviously other ways are possible as you've found. The performance problem is irritating though, and the App.xaml way is also irritating because they don't resolve at design time (at least, they don't for us, if they do for you I want to know why).
However, putting them in App.xaml is the only technique I've found anything approaching an 'official' statement about.
I woulld like to localize my WPF application with resource files. It good technics. But I have requirement to give ability to end user to change some localization information (for example some word traslation). It means change information in the resourse files on the fly (in run time). Is it possible ?
This would involve recompiling the resources on the fly; and reloading them will be quite difficult (as DLLs cannot be unloaded without unloading an AppDomain).
In such a configuration, you're better off using the database to store your translations.