La última versión del programa que se hizo, compuesta por contenedores Blobs y Queues, funcionó correctamente en el equipo local (con Windows Vista 32 bits), devolviendo todas las clases generadas a partir de nuestro "MasterModel" enviado por el cliente.
Al intentar publicar la aplicación en los servidores de Windows Azure, este devolvía el siguiente error: "Could not load file or assembly 'Microsoft.VisualStudio.Modeling.Sdk.Diagrams.GraphObject' or one of its dependencies. An attempt was made to load a program with an incorrect format"
Publicamos un hilo en el foro de microsoft al no encontrar nada al respecto.
http://social.msdn.microsoft.com/Forums/es-ES/vsx/thread/176e14b3-61af-4036-9caf-5fb201868204
En este tema, en resumen, explica que las maquinas donde está alojado Azure son de 64bits, y aunque acepta ensamblados de 32 bits en las aplicaciones que se publican, solo pueden estructurase de una forma específica. En definitiva sugieren que se pruebe la aplicación en equipos locales con un sistema operativo de 64 bits, el entorno más parecido al que existe en el Cloud de microsoft.
Conseguimos entonces, remodelando toda nuestra solución quitando los storages de Azure, hacer funcionar el programa dentro de Azure siguiendo las instrucciones de este magnifico Blog:
jueves, 20 de mayo de 2010
martes, 12 de enero de 2010
Queues y Blobs
Después de leerme documentos y estudiar ejemplos, incorporamos de los blobs y colas (queues), como almacén de datos y comunicación entre el WebRole y el WorkerRole.
En nuestro programa, se crea una cola donde, por cada tipo de modelRoot del archivo xml recivido por el cliente, se obtiene su nombre y se introduce como mensaje. El WorkerRole contiene un bucle esperando a que la cola creada en el WebRole tenga un mensaje, para así empezar la generación del asset específico. Para que saber que no hay que generar más assets, el último mensaje introducido en la cola tiene como texto "end".
Se crea otra cola de en el WorkerRole que tiene la misma función que la anterior pero en la otra dirección, en la cual los mensajes son las clases generadas.
El blob que creamos únicamente se utiliza para almacenar el archivo xml que recibe el WebRole como MemoryStream. El WorkerRole lo utilizará para descargar su contenido.
Saludos
En nuestro programa, se crea una cola donde, por cada tipo de modelRoot del archivo xml recivido por el cliente, se obtiene su nombre y se introduce como mensaje. El WorkerRole contiene un bucle esperando a que la cola creada en el WebRole tenga un mensaje, para así empezar la generación del asset específico. Para que saber que no hay que generar más assets, el último mensaje introducido en la cola tiene como texto "end".
Se crea otra cola de en el WorkerRole que tiene la misma función que la anterior pero en la otra dirección, en la cual los mensajes son las clases generadas.
El blob que creamos únicamente se utiliza para almacenar el archivo xml que recibe el WebRole como MemoryStream. El WorkerRole lo utilizará para descargar su contenido.
public void SendQueue(ModelRoot modelRoot)
{
//Create Queue for send ModelClass
QueueStorage qStore = QueueStorage.Create(StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration());
var q = qStore.GetQueue("radarcsend");
if (!q.DoesQueueExist())
{
q.CreateQueue();
}
foreach (ModelType type in modelRoot.Types)
{
ModelClass modelClass = type as ModelClass;
if (modelClass != null)
{
//Write modelClass to queue
q.PutMessage(new Message(modelClass.Name));
}
}
q.PutMessage(new Message("end"));
}
public override void Start()
{
QueueStorage qStore = QueueStorage.Create(StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration());
//Cola lectora
RoleManager.WriteToLog("Information", "Worker Process entry point called");
var queue = qStore.GetQueue("radarcsend");
if (!queue.DoesQueueExist())
queue.CreateQueue();
else
queue.Clear();
//Cola escritora
var queueWrite = qStore.GetQueue("radarcreceive");
if (!queueWrite.DoesQueueExist())
queueWrite.CreateQueue();
else
queueWrite.Clear();
String stringClass = null;
while (true)
{
Thread.Sleep(10);
Message message = queue.GetMessage();
if (message != null)
{
string messageString = message.ContentAsString();
if (messageString != null)
{
if (messageString == "end")
{
queueWrite.PutMessage(new Message("end"));
queue.DeleteMessage(message);
}
else
{
if (modelRoot == null)
modelRoot = ReadModelRoot();
if (modelRoot != null)
{
queue.DeleteMessage(message);
stringClass = SearchAndCreate(modelRoot, messageString);
queueWrite.PutMessage(new Message(stringClass));
}
}
}
}
}
}
public List<string> WaitResultQueue()
{
List<string> result = null;
QueueStorage qStore = QueueStorage.Create(StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration());
var queue = qStore.GetQueue("radarcreceive");
if (!queue.DoesQueueExist())
{
queue.CreateQueue();
}
Message message = null;
while (true)
{
Thread.Sleep(100);
message = queue.GetMessage();
if (message != null)
{
string messageString = message.ContentAsString();
if (messageString != null)
{
if (messageString == "end")
{
break;
}
else
{
result.Add(messageString);
queue.DeleteMessage(message);
}
}
}
}
queue.DeleteMessage(message);
queue.DeleteQueue();
return result;
}
public void StorageBlob(MemoryStream streamModelRoot)
{
streamModelRoot.Position = 0;
//Create Container for Blob
StorageAccountInfo account = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
BlobStorage storage = BlobStorage.Create(account);
BlobContainer container = storage.GetBlobContainer(@"radarc");
container.CreateContainer(null, ContainerAccessControl.Public);
//Create Blob for storage ModelRoot
string uniqueBlobName = "radarcblob";
BlobProperties prop = new BlobProperties(uniqueBlobName);
prop.ContentType = "ModelRoot";
BlobContents blob = new BlobContents(streamModelRoot);
container.CreateBlob(prop, blob, true);
//RoleManager.WriteToLog("Information", string.Format("Uploaded blob {0} as {1}", fileName, uniqueBlobName));
prop = container.GetBlobProperties(uniqueBlobName);
}
public ModelRoot ReadModelRoot()
{
//Create Container for Blob
StorageAccountInfo account = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
BlobStorage storage = BlobStorage.Create(account);
BlobContainer container = storage.GetBlobContainer(@"radarc");
container.CreateContainer(null, ContainerAccessControl.Public);
string uniqueBlobName = "radarcblob";
if (container.DoesBlobExist(uniqueBlobName))
{
//Read Blob
BlobProperties prop = new BlobProperties(uniqueBlobName);
prop.ContentType = "ModelRoot";
BlobContents blob = new BlobContents(new MemoryStream());
prop = container.GetBlob(uniqueBlobName, blob, false);
MemoryStream memoryStream = blob.AsStream as MemoryStream;
byte[] txt = memoryStream.GetBuffer();
char[] chars=Encoding.UTF8.GetChars(txt);
string models=new string(chars);
if (memoryStream.Length == 0)
return null;
Type[] types = { typeof(Microsoft.VisualStudio.Modeling.Diagrams.CoreDesignSurfaceDomainModel), typeof(BusinessEntitiesDSLDomainModel) };
Microsoft.VisualStudio.Modeling.Store store = new Microsoft.VisualStudio.Modeling.Store(types);
ModelRoot modelR = null;
memoryStream.Position = 0;
using (Transaction t = store.TransactionManager.BeginTransaction())
{
modelR = BusinessEntitiesDSLSerializationHelper.Instance.LoadModel(store, memoryStream, null, null);
t.Commit();
}
return modelR;
}
return null;
}
Saludos
El planteamiento
Habiendo adquirido los conocimientos iniciales en aplicaciones CloudService para Windows Azure, nos centramos en el desarrollo del prototipo para adaptar el motor de generación por plantillas de Radarc a la nube, intentando optimizar su tiempo de generación.
Nada más empezar, nos encontramos con el primer problema. El motor de generación por plantillas que usa el subsistema de generación de Radarc sólo se puede ejecutar bajo el entorno de Visual Studio, por lo que en Azure no podríamos utilizarlo, ya que Visual Studio no se encuentra en la nube. La solución la encontramos en Visual Studio 2010, que incorpora una herramienta denominada "Precompiled Text Template" que nos sirvió para sustituir el motor de generación por plantillas y las plantillas de Radarc por clases generadoras de código que representen a dichas plantillas.
Diseñamos, inicialmente, la estructura de nuestro proyecto. La primera parte consta de un cliente que envía el modelo en xml y que luego recibe el resultado (las clases generadas). La segunda parte, el programa que se aloja en Azure, es un WebRole que recibe el modelo del cliente, lo adecúa para tratarlo, y lo envía al WorkerRole para que éste mediante las librerías del motor de generación por plantillas genere los assets correspondientes.
Creamos un proyecto CloudService, con un WebRole y un WorkerRole. Desde el WebRole llamamos a los métodos del WorkerRole como en un programa normal de escritorio. Creíamos que sería sencillo la comunicación entre los roles de la aplicación en Azure, pero ya en la ejecución local del programa vimos que no podía hacerse de esa manera. Por lo tanto, dedicamos el tiempo a buscar algún otro ejemplo un poco más complejo, que tuviera un WebRole y un WorkerRole, dandonos cuenta de que la comunicación entre ellos por lo general se realizaba con Blobs, Queues y Tables.
Visto los ejemplos, nos pusimos manos a la obra para adaptar el programa que ya teníamos a la comunicación mediante el Cloud Storage de Azure.
Nada más empezar, nos encontramos con el primer problema. El motor de generación por plantillas que usa el subsistema de generación de Radarc sólo se puede ejecutar bajo el entorno de Visual Studio, por lo que en Azure no podríamos utilizarlo, ya que Visual Studio no se encuentra en la nube. La solución la encontramos en Visual Studio 2010, que incorpora una herramienta denominada "Precompiled Text Template" que nos sirvió para sustituir el motor de generación por plantillas y las plantillas de Radarc por clases generadoras de código que representen a dichas plantillas.
Diseñamos, inicialmente, la estructura de nuestro proyecto. La primera parte consta de un cliente que envía el modelo en xml y que luego recibe el resultado (las clases generadas). La segunda parte, el programa que se aloja en Azure, es un WebRole que recibe el modelo del cliente, lo adecúa para tratarlo, y lo envía al WorkerRole para que éste mediante las librerías del motor de generación por plantillas genere los assets correspondientes.
Creamos un proyecto CloudService, con un WebRole y un WorkerRole. Desde el WebRole llamamos a los métodos del WorkerRole como en un programa normal de escritorio. Creíamos que sería sencillo la comunicación entre los roles de la aplicación en Azure, pero ya en la ejecución local del programa vimos que no podía hacerse de esa manera. Por lo tanto, dedicamos el tiempo a buscar algún otro ejemplo un poco más complejo, que tuviera un WebRole y un WorkerRole, dandonos cuenta de que la comunicación entre ellos por lo general se realizaba con Blobs, Queues y Tables.
Visto los ejemplos, nos pusimos manos a la obra para adaptar el programa que ya teníamos a la comunicación mediante el Cloud Storage de Azure.
Suscribirse a:
Comentarios (Atom)