InfoPath como aplicación es capaz de generar documentos XML que contienen no solo la información también la estructura del mismo.
Utilizando la herramienta XSD.exe es posible generar una clase que facilite manipular dicha información (http://msdn.microsoft.com/en-us/library/bb251017.aspx). Sin embargo, es específica para cada documento.
En muchas oportunidades sucede que se requiere codificar (por ejemplo un flujo de trabajo), para múltiples documentos y formatos.
Para facilitar estas actividades, se me ocurrió definir una clase que administre genéricamente el contenido de documentos InfoPath.
Esta clase recibe un elemento de una biblioteca de documentos InfoPath de SharePoint y carga el documento en memoria para facilitar su manipulación.
Comencemos con la lista de importaciones y variables necesarias.
Imports System.Xml.Serialization Imports System.Xml ''' <summary> ''' Permite manipular el contenido de un documento de InfoPath en algo fácilmente accesible por código ''' </summary> ''' <remarks>Carga el contenido del documento, adjunto a una biblioteca de documentos de MOSS ''' y crea listas fácilmente accesibles tanto de los atributos como de los valores (elementos) ''' </remarks> Public Class InfoPathConverter ''' <summary> ''' Documento conteniendo todo el documento InfoPath ''' </summary> ''' <remarks></remarks> Dim xDoc As XDocument = Nothing ''' <summary> ''' Lista de atributos ''' </summary> ''' <remarks></remarks> Dim atrs As Dictionary(Of String, XAttribute) ''' <summary> ''' lista de valores (elementos) ''' </summary> ''' <remarks></remarks> Dim els As Dictionary(Of String, XElement)
Imports System.Xml.Serialization
Imports System.Xml
''' <summary>
''' Permite manipular el contenido de un documento de InfoPath en algo fácilmente accesible por código
''' </summary>
''' <remarks>Carga el contenido del documento, adjunto a una biblioteca de documentos de MOSS
''' y crea listas fácilmente accesibles tanto de los atributos como de los valores (elementos)
''' </remarks>
Public Class InfoPathConverter
''' Documento conteniendo todo el documento InfoPath
''' <remarks></remarks>
Dim xDoc As XDocument = Nothing
''' Lista de atributos
Dim atrs As Dictionary(Of String, XAttribute)
''' lista de valores (elementos)
Dim els As Dictionary(Of String, XElement)
Una de las características que me suelen ser necesarias es la de asegurarme que existan ciertas propiedades y atributos en el documento ya que son utilizados en la lógica del flujo.
Por ello, la clase expone 2 propiedades para contener los atributos y los campos que son requeridos.
''' <summary> ''' Lista de nombres de atributos requeridos en el documento ''' </summary> ''' <remarks></remarks> Private mAtributes As List(Of String) ''' <summary> ''' Define que atributos son necesarios en el documento para considerarlo válido ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property AttributesNeeded() As List(Of String) Get If mAtributes Is Nothing Then mAtributes = New List(Of String) mAtributes.Add("Etapa") End If Return mAtributes End Get End Property Private mFieldsNeeded As List(Of String) ''' <summary> ''' Define que campos son necesarios en el documento para considerarlo válido ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property FieldsNeeded() As List(Of String) Get If mFieldsNeeded Is Nothing Then mFieldsNeeded = New List(Of String) End If Return mFieldsNeeded End Get End Property
''' Lista de nombres de atributos requeridos en el documento
Private mAtributes As List(Of String)
''' Define que atributos son necesarios en el documento para considerarlo válido
''' <value></value>
''' <returns></returns>
Public ReadOnly Property AttributesNeeded() As List(Of String)
Get
If mAtributes Is Nothing Then
mAtributes = New List(Of String)
mAtributes.Add("Etapa")
End If
Return mAtributes
End Get
End Property
Private mFieldsNeeded As List(Of String)
''' Define que campos son necesarios en el documento para considerarlo válido
Public ReadOnly Property FieldsNeeded() As List(Of String)
If mFieldsNeeded Is Nothing Then
mFieldsNeeded = New List(Of String)
Return mFieldsNeeded
''' <summary> ''' Carga en las listas el contenido del documento InfoPath ''' </summary> ''' <param name="item">Item de la biblioteca de docuemntos, conteniendo el mismo</param> ''' <remarks>Carga el contenido del documento, adjunto a una biblioteca de documentos de MOSS ''' y crea listas fácilmente accesibles tanto de los atributos como de los valores (elementos) ''' </remarks> Sub getDocumentContent(ByVal item As SPListItem) 'La propiedad File expone el documento InfoPath Dim xtextr As New XmlTextReader(item.File.OpenBinaryStream) 'Se carga entonces el documento desde el Stream xDoc = XDocument.Load(xtextr) 'Obtiene los atributos atrs = (From x As XAttribute In xDoc.Root.Attributes).ToDictionary( _ Of String)(Function(x) x.Name.LocalName.ToUpper) ' Evalúa si todos los atributos requeridos están pesentes For Each s As String In AttributesNeeded Dim lookFor As String = s.ToUpper If (From a As XAttribute In atrs.Values _ Where a.Name.LocalName.ToUpper = lookFor).ToArray.Length < 1 Then Throw New Exception("Formulario inválido: le falta el atributo " & s) End If Next ' Evalúa lo mismo para los campos (Elements) els = (From v As XElement In xDoc.Root.Elements).ToDictionary( _ Of String)(Function(v) v.Name.LocalName.ToUpper) For Each s As String In FieldsNeeded Dim lookFor As String = s.ToUpper If (From a As XElement In els.Values _ Where a.Name.LocalName.ToUpper = lookFor).ToArray.Length < 1 Then Throw New Exception("Formulario inválido: le falta el campo " & s) End If Next End Sub Teniendo el documento en memoria, se pueden exponer los valores y asignarles nuevos con estos métodos: ''' <summary> ''' Cambia el valor de un atributo ''' </summary> ''' <param name="what">Nombre del atributo</param> ''' <param name="newValue">Nuevo Valor</param> ''' <remarks></remarks> Sub ChangeAttribute(ByVal what As String, ByVal newValue As String) If atrs.ContainsKey(what.ToUpper) Then atrs(what.ToUpper).Value = newValue End If End Sub ''' <summary> ''' Obtiene el valor de uhn atributo ''' </summary> ''' <param name="what">Nombre del atirbuto</param> ''' <returns>Contenido del mismo (siempr como cadena de caracteres) o valor nulo si no existe ''' </returns> ''' <remarks></remarks> Function ReadAttribute(ByVal what As String) As String If atrs.ContainsKey(what.ToUpper) Then Return atrs(what.ToUpper).Value Else Return Nothing End If End Function ''' <summary> ''' Cambia el valor de un elemento ''' </summary> ''' <param name="what">Nombre del elemento</param> ''' <param name="newValue">Valor a asignar</param> ''' <remarks></remarks> Sub ChangeValue(ByVal what As String, ByVal newValue As String) If els.ContainsKey(what.ToUpper) Then els(what.ToUpper).Value = newValue End If End Sub ''' <summary> ''' Obtiene le valor de un elemento ''' </summary> ''' <param name="what">Nombre del elemento a leer</param> ''' <returns>Valor del elemento (siempre como cadena de caracteres), o valor nulo si no existe ''' </returns> ''' <remarks></remarks> Function ReadValue(ByVal what As String) As String If els.ContainsKey(what.ToUpper) Then Return els(what.ToUpper).Value Else Throw New KeyNotFoundException("El campo " & what & " no se encuentra en el documento") End If End Function
''' Carga en las listas el contenido del documento InfoPath
''' <param name="item">Item de la biblioteca de docuemntos, conteniendo el mismo</param>
Sub getDocumentContent(ByVal item As SPListItem)
'La propiedad File expone el documento InfoPath
Dim xtextr As New XmlTextReader(item.File.OpenBinaryStream)
'Se carga entonces el documento desde el Stream
xDoc = XDocument.Load(xtextr)
'Obtiene los atributos
atrs = (From x As XAttribute In xDoc.Root.Attributes).ToDictionary( _
Of String)(Function(x) x.Name.LocalName.ToUpper)
' Evalúa si todos los atributos requeridos están pesentes
For Each s As String In AttributesNeeded
Dim lookFor As String = s.ToUpper
If (From a As XAttribute In atrs.Values _
Where a.Name.LocalName.ToUpper = lookFor).ToArray.Length < 1 Then
Throw New Exception("Formulario inválido: le falta el atributo " & s)
Next
' Evalúa lo mismo para los campos (Elements)
els = (From v As XElement In xDoc.Root.Elements).ToDictionary( _
Of String)(Function(v) v.Name.LocalName.ToUpper)
For Each s As String In FieldsNeeded
If (From a As XElement In els.Values _
Throw New Exception("Formulario inválido: le falta el campo " & s)
End Sub
Teniendo el documento en memoria, se pueden exponer los valores y asignarles nuevos con estos métodos:
''' Cambia el valor de un atributo
''' <param name="what">Nombre del atributo</param>
''' <param name="newValue">Nuevo Valor</param>
Sub ChangeAttribute(ByVal what As String, ByVal newValue As String)
If atrs.ContainsKey(what.ToUpper) Then
atrs(what.ToUpper).Value = newValue
''' Obtiene el valor de uhn atributo
''' <param name="what">Nombre del atirbuto</param>
''' <returns>Contenido del mismo (siempr como cadena de caracteres) o valor nulo si no existe
''' </returns>
Function ReadAttribute(ByVal what As String) As String
Return atrs(what.ToUpper).Value
Else
Return Nothing
End Function
''' Cambia el valor de un elemento
''' <param name="what">Nombre del elemento</param>
''' <param name="newValue">Valor a asignar</param>
Sub ChangeValue(ByVal what As String, ByVal newValue As String)
If els.ContainsKey(what.ToUpper) Then
els(what.ToUpper).Value = newValue
''' Obtiene le valor de un elemento
''' <param name="what">Nombre del elemento a leer</param>
''' <returns>Valor del elemento (siempre como cadena de caracteres), o valor nulo si no existe
Function ReadValue(ByVal what As String) As String
Return els(what.ToUpper).Value
Throw New KeyNotFoundException("El campo " & what & " no se encuentra en el documento")
Finalmente ento0nces, con un método Save, se puede guardar en la lista de origen... o en otra. Para ello, se le envía al método el ListItem que contendrá el documento.
''' <summary> ''' Guarda el contenido de los valores y atributos en el documento InfoPath actualizando los mismos ''' </summary> ''' <param name="item"></param> ''' <remarks></remarks> Public Sub Save(ByVal item As SPListItem) item.File.CheckOut() Dim memoryStream As New IO.MemoryStream() Dim sett As New XmlWriterSettings sett.Encoding = System.Text.Encoding.UTF8 sett.OmitXmlDeclaration = False Dim xmlTextWriter As XmlWriter = XmlWriter.Create(memoryStream, sett) xDoc.Save(xmlTextWriter) xmlTextWriter.Flush() memoryStream.Position = 0 item.File.SaveBinary(memoryStream.GetBuffer) item.File.CheckIn("") End Sub
''' Guarda el contenido de los valores y atributos en el documento InfoPath actualizando los mismos
''' <param name="item"></param>
Public Sub Save(ByVal item As SPListItem)
item.File.CheckOut()
Dim memoryStream As New IO.MemoryStream()
Dim sett As New XmlWriterSettings
sett.Encoding = System.Text.Encoding.UTF8
sett.OmitXmlDeclaration = False
Dim xmlTextWriter As XmlWriter = XmlWriter.Create(memoryStream, sett)
xDoc.Save(xmlTextWriter)
xmlTextWriter.Flush()
memoryStream.Position = 0
item.File.SaveBinary(memoryStream.GetBuffer)
item.File.CheckIn("")
Si si, ya sé. quieres verlo completo. Pues aquí está la clase entera. http://blogs.solidq.com/ES/dseara/Archivos/InfoPathConverter.zip
CREATE TABLE [dbo].[Roles](
[RoleID] [uniqueidentifier] NOT NULL,
[RoleName] [nvarchar](260) NOT NULL,
[Description] [nvarchar](512) NULL,
[TaskMask] [nvarchar](32) NOT NULL,
[RoleFlags] [tinyint] NOT NULL,
CONSTRAINT [PK_Roles] PRIMARY KEY NONCLUSTERED
(
[RoleID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE UNIQUE CLUSTERED INDEX [IX_Roles] ON [dbo].[Roles]
[RoleName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'114e91eb-1868-4cf7-8e9d-f43a19813b7f', N'Browser', N'May view folders, reports and subscribe to reports.', N'0010101001000100', 0)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'9bc89cad-3d9a-491d-be02-75be1579af2c', N'Content Manager', N'May manage content in the Report Server. This includes folders, reports and resources.', N'1111111111111111', 0)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'0286b7fb-a18b-4fa4-bb59-adb7cf28df73', N'Model Item Browser', N'Allows users to view model items in a particular model.', N'1', 2)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'29c8f388-b3f6-4a4d-a7d9-eed72f3c0bd2', N'My Reports', N'May publish reports and linked reports; manage folders, reports and resources in a users My Reports folder.', N'0111111111011000', 0)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'5d9fa665-e315-4249-b519-0e3668f3d49d', N'Publisher', N'May publish reports and linked reports to the Report Server.', N'0101010100001010', 0)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'e51e9553-4f47-4619-a943-05020a373862', N'Report Builder', N'May view report definitions.', N'0010101001000101', 0)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'8ca532d7-7e5c-4f18-8976-d2d4ffd95472', N'System Administrator', N'View and modify system role assignments, system role definitions, system properties, and shared schedules.', N'110101011', 1)
INSERT [dbo].[Roles] ([RoleID], [RoleName], [Description], [TaskMask], [RoleFlags]) VALUES (N'a5f16ea9-fb16-4898-b8f1-9d05351f56de', N'System User', N'View system properties and shared schedules.', N'001010001', 1)
Podemos elegir al generar el script la versión de SQL Server (2000, 2005 o 2008) Como pequeño tirón de orejas , indicar que el ejemplo anterior ha sido generado para "SQL Server 2008" y vemos que no se están utilizando los nuevos constructores de fila para generar los insert.
Quizás el aspecto más importante, por el control que nos permite tener sobre nuestros servidores SQL Server, es el nuevo marco de trabajo de gestión declarativo, que nos permite definir políticas que deben de cumplirse en instancias, bases de datos u objetos, pero esta novedad se analiza en el artículo SQL Server 2008 Declarative Management Framework, por lo que no entraremos a fondo en su estudio, pero que debemos de mencionar al menos.
Otra de las novedades interesantes es la posibilidad de cifrar, de forma transparente a usuarios y aplicaciones, nuestras bases de datos. En SQL Server 2005, se introdujo una arquitectura de cifrado, que nos permitía utilizar funciones para cifrar, utilizando certificados o claves, los datos almacenados en las bases de datos SQL Server 2005. Sin embargo, eso nos exigía establecer procesos que realizasen las operaciones de cifrado y descifrado de datos, y además, con algunas restricciones que fundamentalmente afectaban al rendimiento. En SQL Server 2008, a través de la característica denominada Transparent Data Encryption(TDE), que solventa esas limitaciones, del modo más rápido y eficiente posible: se cifra la base de datos completa. El cifrado de datos con TDE se realiza a nivel de Entrada / Salida, a través del Buffer Pool. Esto quiere decir, que cuando se habilita una base de datos para TDE, se cifran todos los ficheros de dicha base de datos, tanto de datos como de log de transacciones, y el cifrado y descifrado se realizará durante las operaciones de lectura y escritura en disco. La gran ventaja de esta aproximación, como hemos comentado, es que lo hace cien por cien transparente a las aplicaciones, sin embargo, el problema es que los datos en memoria no se encuentran cifrados, y determinadas operaciones, como paginación de Sistema Operativo, o un Dump de memoria, pueden llevar disco los datos sin cifrar. Sin embargo, lo que si se tiene en cuenta, es que cuando habilitamos TDE en una base de datos, automáticamente se configura tempdb con TDE también, para que todos los objetos temporales que sea necesario crear, sean también cifrados. Del mismo modo, tanto las instantáneas, como las copias de seguridad, pueden sacar provecho de esta característica y también se cifrarán. Especial mención, requiere la copia de seguridad. Como ocurre siempre en estos casos, deberemos de disponer de copias de seguridad de los objetos (certificados o claves) que utilicemos con TDE, para que en caso de que necesitemos realizar una restauración, seamos capaces de poder leer los datos. Si no disponemos de esos objetos, no seremos capaces de restaurar una copia de seguridad cifrada con TDE.
Existen algunos cambios, que aunque no son excesivamente relevantes, si merecen mencionarse, en los roles de la base de datos msdb. En primer lugar los roles para la gestión de seguridad de SQL Server Integration Services cambian de nombre y pasan de llamarse db_dtsadmin, db_dtsltduser y db_dtsoperator se han renombrado respectivamente a db_ssisadmin, db_ssisltduser y db_ssisoperator. En el caso de que estemos realizando una actualización desde SQL Server 2005, los roles antigüos se mantendrán y se añadirán como miembros de estos nuevos roles para mantener la compatibilidad.
Además de estos cambios de nomenclatura, aparecen nuevos roles de base de datos, para dar soporte a algunas de las nuevas funcionalidades, especialmente para las nuevas características de gestión. Dispondremos en la base de datos msdb, de los siguientes nuevos roles:
· ServerGroupAdministratorRole y ServerGroupReaderRole, que nos permiten gestionar los grupos de servidores para administración centralizada.
· PolicyAdministratorRole, que nos permite definir los usuarios administradores de la gestión basada en políticas
· dc_admin, dc_operator y dc_proxy, que utilizaremos con el componente data collector
El pasado día 21 de abril en Madrid y el día 22 de abril en Barcelona tuvo lugar el evento Frameworks y herramientas RAD de código abierto y propietario para soluciones .NET. Donde presenté nuestro Solid RAD, una herramienta para el desarrollo rápido de aplicaciones centradas en datos con una arquitectura de dos y tres capas.
Si estáis interesados en Solid RAD Tenéis disponibles unos vídeos en mms://solidq.com/SolidRad .
NOTA: copiad y pegad mms://solidq.com/SolidRad en la barra de direcciones de IE para ver los vídeos.
Como lo prometido es deuda, y como más vale tarde que nuncaJ, aquí van las demos de las novedades de BI para SQL Server 2008.
Novedades SSAS 2008 Demo
Esta demo consta de dos partes:
1. Se hace un breve repaso sobre las nuevas DMVs creadas en 2008 para monitorizar Analisis Services.
2. Se crea una solución SSAS desde cero mostrando los nuevos asistentes para la generación de cubos y dimensiones.
Novedades SSIS 2008 Demo
Esta demo consta de
1. Muestra un ejemplo de cómo trabajar con los nuevos tipos de datos fecha y hora de SQL 2008-03-18.
2. Las novedades para la transformación Lookup y como trabajar con ellas.
3. Un vistazo rápido sobre los conectores ADO.NET
4. Como trabajar con la nueva tarea data profiling y como visionar posteriormente los datos obtenidos a través del data Profile viewer.
Novedades SSRS 2008 Demo
Esta demo hace un repaso por el nuevo diseñador de informes, muestra como trabajar con el nuevo objeto Tablix así como un repaso sobre las mejoras de los gráficos y los nuevos controles gauge.
Un saludo a todos
Anoche tuve el privilegio de cenar en Redmond (cerca de Seattle, en los USA) con tres personas brillantes, tres ingenieros en ciernes, que pronto obtendrán su título (dos en informática y uno en arquitectura).
Es una delicia ver a tres personas jóvenes, no pasan de los 22, con ganas de comerse el mundo, y con desprecio total a las trabas que para otros son insalvables (distancia, idioma, relaciones laborales inusuales). Dos de ellos vienen de la Comunidad Valenciana a trabajar en Microsoft durante unos meses, y estoy seguro de que su presencia se hará notar en esta mega-corporación, de un modo u otro.
Están escribiendo un blog en El País, http://blogs.elpais.com/un_verano_en_microsoft/, para documentar su experiencia por esas tierras.
Ingenieros como estos serán los que muy pronto llevarán las riendas tecnológicas de nuestro país, relevando exitosamente a la generación de los que aprendimos informática a matacaballo, como un accesorio más de otros estudios, y mediante largas y dolorosas, aunque excitantes, sesiones de auto-aprendizaje.
En nuestra empresa tenemos la suerte de contar con unos pocos ingenieros jóvenes también, muy pocos y muy selectos, pero con una capacidad de evolución personal y profesional admirable. Estos jóvenes muestran el mismo brillo en la mirada que los otros mentores de la empresa, más experimentados que ellos, que les ayudan en su camino hacia la excelencia tecnológica y profesional.
Estos son los profesionales que podrán cambiar para siempre, no solamente la posición de la informática en las empresas, sino incluso las relaciones laborales dentro de las empresas en las que trabajen. Esto es como la esclavitud, si siempre has sido esclavo, quizá no pienses que la libertad sea tan importante, pero si alguna vez saboreas la libertad, aunque solo sea por un corto espacio de tiempo, nunca más aceptarás la esclavitud como una forma de vida aceptable. Ahora que estos jóvenes están probando lo que es trabajar en un entorno basado en la confianza y en el respeto profesional por las personas, nunca aceptarán otro tipo de relación.
Esta nueva generación tiene ideas brillantes, aunque quizá no sean conscientes de ello aún, y capacidad de aprendizaje para llevarlas a cabo algún día. Es nuestra responsabilidad el rodearles del entorno adecuado para permitirles lograr sus objetivos, con lo que lograrán traer un mundo mejor para toda nuestra sociedad.
¿Que estoy exagerando? ¿Que los cambios de unos pocos no pueden cambiar la sociedad? Las sociedades solo cambian persona a persona, no hay otro modo. Y tengo la suerte de estar rodeado en nuestra empresa por personas que trabajan activamente para lograr este cambio.
Tengo la sensación de que ayer cené con algunos de estos motores del cambio futuro.
¡Me encanta!
Fernando
Paso 1: Para crear la llave: sn -k MiLLave.snk
Un archivo es suficiente para una organización de desarrollo. No se requiere 1 llave por aplicación.
Paso 2: Agregar la referencia al assembly (Ejecutable, DLL o Sitio Web) en el archivo Assembly Info.
[assembly:AssemblyKeyFile(@"c:\Llave\MiLLave.snk")]
Paso 3: Agregar una política que permita la ejecución de assemblies con esa llave y asignarle los permisos adecuados.
Esto se hace en Administrative tools .NET Framework 2.0 Configuration,
a) Navegar al Runtime Security Policy y con clic derecho sobre Runtime Security Policy escoger Trust Assembly.
b) Escoger donde se harán los cambios (maquina)
c) Escoger la ruta del assembly firmado.
d) Cambiar la opción para que sean All Assemblies with the same assembly public key.
e) Definir el nivel de acceso mínimo requerido por la aplicación.
f) Finish
Paso 4: Ponerle nombre al grupo de código.
El wizard genera un grupo de código llamado Wizard_0 que queda en Machine, Code Groups. Con clic derecho renombrarlo (Gilgal). También puede moverse a debajo de otra de los códigos de grupo, por ejemplo moverlo debajo de LocalIntranet con drag and drop.
Paso 5: Validar que la aplicación corre. Con estos permisos.
Paso 6: Crear instalador
Hacer clic derecho sobre RunTime security Policy y escoger Create Deployment Package
a) Seleccionar Machine.
b) Seleccionar una ruta y escribir un nombre de archivo MSI.
c) Next
d) Finish
Paso 7: Ejecutar el MSI donde sea necesario.