Buenas
un post un post un poco espeso sobre un error más espeso aún con el que tuve que lidiar durante un par de semanas.
Introducción
Resulta que cuando realizas operaciones dentro del IDE de Visual Studio 2005 que necesiten trabajar con un IsolatedStorage te encuentras con una excepción del tipo IsolatedStorageException:
System.IO.IsolatedStorage.IsolatedStorageException occurred
Message="Unable to determine the identity of domain."
Source="mscorlib"
StackTrace:
at System.IO.IsolatedStorage.IsolatedStorage._GetAccountingInfo(Evidence evidence, Type evidenceType, IsolatedStorageScope fAssmDomApp, Object& oNormalized)
at System.IO.IsolatedStorage.IsolatedStorage.GetAccountingInfo(Evidence evidence, Type evidenceType, IsolatedStorageScope fAssmDomApp, String& typeName, String& instanceName)
at System.IO.IsolatedStorage.IsolatedStorage._InitStore(IsolatedStorageScope scope, Evidence domainEv, Type domainEvidenceType, Evidence assemEv, Type assemblyEvidenceType, Evidence appEv, Type appEvidenceType)
at System.IO.IsolatedStorage.IsolatedStorage.InitStore(IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
at System.IO.IsolatedStorage.IsolatedStorageFile.GetStore(IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
at System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForDomain()
at ElBruno.Dsl20.IsolatedStorageHelper.GetIsolatedStorageMaxiumSixe()
Y seguramente, más de uno se preguntará ¿para que quiero trabajar con un IsolatedStorage?; pues un ejemplo puede ser el tratamiento de strings con un StreamWriter, porque cuando el tamaño del mismo en memoria sobrepasa cierto tamaño comienza a "bajar a disco" para realizar algunas operaciones. Es en este momento, cuando internamente el Framework solicita permisos para la creación de un IsolatedStorageFile y las operaciones se realizan en el ámbito del mismo.
Problema
Pero desde el IDE de Visual Studio, el escenario se complica un poco. Porque, por ejemplo, cuando ejecutas tu aplicacion en el Visual Studio Experimental Hive, el System.AppDomain principal del IDE no tiene identidad. Ya se que esto parece imposible, pero la siguiente imagen vale mas que mil cervezas lo muestra clarito:
Es por esto que frente a cualquier tipo de acción utilizando un IsolatedStorage, la exception "Unable to determine the identity of domain." es lanzada.
Solución
Hace un tiempo, posteé este problema en los foros de Extensibilidad ed Visual Studio, pero después de verlo con la gente de Microsoft, no tuve respuesta. Así que me puse a estudiar un poco y encontré un workaround más que obvio para solucionar este problema:
¡¡¡ Ejecuta tus acciones en otro AppDomain con los permisos y evidencias necesarios !!!
He aquí un ejemplo para demostrar como solucionarlo. El siguiente DSL posee una validación en la clase ExampleModel.partial.cs; que cuando es invocada, muestra el tamaño por defecto para un IsolatedStorage para el usuario actual. Para esto se vale de una clase IsolatedStorageHelper con el siguiente código dentro de la misma.
Nota: sobre las validaciones y las Domain Specific Language Tools pueden leer mi anterior post aquí
IsolatedStorageHelper.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.IO.IsolatedStorage;
5 using System.IO;
6
7 namespace ElBruno.Dsl20
8 {
9 public class IsolatedStorageHelper : MarshalByRefObject
10 {
11 /// <summary>
12 /// Gets the isolated storage maxium sixe.
13 /// </summary>
14 /// <returns></returns>
15 public double GetIsolatedStorageMaxiumSixe()
16 {
17 IsolatedStorageFile isoFile;
18 isoFile = IsolatedStorageFile.GetUserStoreForDomain();
19
20 // Open or create a writable file.
21 IsolatedStorageFileStream isoStream =
22 new IsolatedStorageFileStream(GetTemporalFileName(),
23 FileMode.OpenOrCreate,
24 FileAccess.Write,
25 isoFile);
26
27 StreamWriter writer = new StreamWriter(isoStream);
28 writer.WriteLine(Guid.NewGuid().ToString());
29
30 // Calculate the amount of space used to record the user's preferences.
31 double d = isoFile.CurrentSize / isoFile.MaximumSize;
32 Console.WriteLine("CurrentSize = " + isoFile.CurrentSize.ToString());
33 Console.WriteLine("MaximumSize = " + isoFile.MaximumSize.ToString());
34
35 // StreamWriter.Close implicitly closes isoStream.
36 writer.Close();
37 isoFile.Dispose();
38 isoFile.Close();
39 return d;
40 }
41
42 /// <summary>
43 /// Gets the name of the temporal file.
44 /// </summary>
45 /// <returns></returns>
46 private static string GetTemporalFileName()
47 {
48 string tempFile = string.Format("temp{0}.xml", Guid.NewGuid().ToString());
49 RemoveFileIfExists(tempFile);
50 return tempFile;
51 }
52
53 /// <summary>
54 /// Removes the file if exists.
55 /// </summary>
56 /// <param name="outputFile">The output file.</param>
57 private static void RemoveFileIfExists(string outputFile)
58 {
59 if (System.IO.File.Exists(outputFile))
60 {
61 System.IO.File.Delete(outputFile);
62 }
63 }
64 }
65 }
66
Dentro de una clase personalizada que he agregado a mi proyecto DSL, ejecuto la función GetIsolatedStorageMaxiumSixe() y muestro el resultado al usuario. Sin embargo si creo la clase IsolatedStorageHelper de manera convencional, obtengo la excepcion mencionada.
helper = new IsolatedStorageHelper();
isolatedStorageMaxiumSixe = helper.GetIsolatedStorageMaxiumSixe();
Es por esto que he implementado la creación de la clase en un nuevo System.AppDomain como muestran las líneas 43 a 74 en el código de la clase que implementa la validación para el diagrama creado con las Domain Specific Language Tools:
ExampleModel.partial.cs
1 using Microsoft.VisualStudio.Modeling.Validation;
2 using System.IO.IsolatedStorage;
3 using System.IO;
4 using System;
5 using System.Threading;
6 using System.Security.Principal;
7 using System.Security.Permissions;
8 using System.Runtime.InteropServices;
9 using System.Reflection;
10 using System.Security.Policy;
11 using System.Security;
12 using System.Windows.Forms;
13
14 namespace ElBruno.Dsl20
15 {
16
17 [ValidationState(ValidationState.Enabled)]
18 public partial class ExampleModel
19 {
20
21 /// <summary>
22 /// Validates the duplicated users E mail.
23 /// </summary>
24 /// <param name="context">The context.</param>
25 [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
26 [System.Security.SecurityTreatAsSafe()]
27 [System.Security.SuppressUnmanagedCodeSecurity()]
28 private void ValidateDuplicatedUsersEMail(ValidationContext context)
29 {
30 try
31 {
32 // defines the name and type for the assembly creation
33 string assemblyName = Assembly.GetExecutingAssembly().FullName;
34 string typeName = "ElBruno.Dsl20.IsolatedStorageHelper";
35
36 // validate user preferences
37 DialogResult res = System.Windows.Forms.MessageBox.Show("Execute IsolatedStorage in new AppDomain ??", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
38 IsolatedStorageHelper helper = null;
39 double isolatedStorageMaxiumSixe = 0;
40
41 if (res == DialogResult.Yes)
42 {
43 // ---------------------------------------------------------------
44 // Create and execute assembly in new AppDomain
45 // ---------------------------------------------------------------
46
47 // Set up the AppDomainSetup
48 AppDomainSetup setup = new AppDomainSetup();
49 setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory.ToString();
50 SecurityZone zone = SecurityZone.MyComputer;
51
52 // Set up the Evidence
53 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
54 Evidence evidence = new Evidence(baseEvidence);
55 evidence.AddAssembly(assemblyName);
56 evidence.AddHost(new Zone(zone));
57
58 AppDomain app = AppDomain.CreateDomain("Processor AppDomain", evidence, setup);
59
60 try
61 {
62
63 helper = (IsolatedStorageHelper)app.CreateInstanceAndUnwrap(assemblyName, typeName);
64 isolatedStorageMaxiumSixe = helper.GetIsolatedStorageMaxiumSixe();
65
66 }
67 catch
68 {
69 throw;
70 }
71 finally
72 {
73 AppDomain.Unload(app);
74 }
75 }
76 else
77 {
78 // ---------------------------------------------------------------
79 // Create and execute assembly in Visual Studio IDE AppDomain
80 // ---------------------------------------------------------------
81 helper = new IsolatedStorageHelper();
82 isolatedStorageMaxiumSixe = helper.GetIsolatedStorageMaxiumSixe();
83 }
84
85 // display result
86 MessageBox.Show(string.Format("Isolated Storage Maxium Sixe: {0}", isolatedStorageMaxiumSixe.ToString()));
87
88 }
89 catch (Exception ex)
90 {
91 System.Windows.Forms.MessageBox.Show(ex.ToString());
92 }
93 }
94 }
95 }
Cuando ejecutamos el DSL y presionamos la opción Validate sobre el menú contextual en nuestro diagrama, veremos el siguiente diálogo de confirmación:
Si seleccionamos NO y nuestra clase se instancia dentro del mismo System.AppDomain que el que esta utilizando Visual Studio, veremos que se dispara la excepción IsolatedStorageException:
Si en cambio, instanciamos nuestra clase dentro de un nuevo System.AppDomain con los privilegios necesarios, la ejecución irá de maravillas y podremos festejar con unas cañas:
Si alguien está interesado en adentrarse un poco más en el tema, puede bajar el proyecto de ejemplo desde aquí (gracias Geeks.ms) y si encuentra algun otro workaround o más información al respecto y quiere compartirla, me avisa :D
Descarga: http://geeks.ms/files/folders/elbruno/entry44654.aspx
Saludos @ La Finca
El Bruno
Crossposting from
ElBruno.com