Social Icons

jueves, 9 de julio de 2015

¿Es JavaScript El Traje Nuevo del Emperador?

Como en el cuento del traje nuevo del emperador... alguien tiene que decirlo...


Script (computing), un programa pequeño y no compilado escrito para un intérprete de comandos o un lenguaje de scripting.

Si JavaScript tiene Script en el nombre, ya te esta dando pistas de que no es el lenguaje de programación adecuado para basar toda la web y la mitad del software de moviles.

Si JavaScript: The good parts es un superventas y solo tiene 150 páginas (y 50 son apendices y solo hay dos de características bonitas del lenguaje y estoy seguro de que hasta el mismísimo Señor Crockford sudó tinta para escribir tantas)

Si te piden que vayas migrando de versión a versión de vez en cuando porque tu proveedor de software va a dejar de soportar tu aplicación en los próximos cinco años, ¿Qué te hace pensar que es una buena idea descargarte e instalar en el corazón de tu software un archivo js minimizado que no puedes leer y que quién sabe de donde viene y cuyo desarrollador se olvidó de el cinco días después de publicarlo?

¿Trabajaré con el?

Claro que sí. De hecho llevo años trabajando con javascript (lustros), pero no a este nivel. Si puedes hacer cualquier cosa con una máquina de Turing ¿Por qué no adoptar un lenguaje de scripting para hacer aplicaciones de miles de líneas? Los valientes llamarían a eso un desafío.

He estado creando clases y constructores y herencia y todo eso se puede hacer en JS pero traducir las vetustas estructuras y patrines OO al modernísimo JS no parece el camino correcto y, seguramente ahí está mi problema. En lugar de abrazar el nuevo lenguaje estoy intentando traducir mis viejos chistes. Y esto cambiará cuando aprenda los chistes nuevos.

El hecho de que no tengamos otra opción también tiene su peso en la decisión. Si trabajas para la web eres libre de elegir entre programar con JavasScript o no trabajar para la web à la Apple.

Entiendo sus ventajas?

La curva de aprendizaje es estupenda, ya que las bases son más simples. No hay tipos ni red de seguridad. No hace falta un IDE ni tampoco hay grandes IDEs, si vienes de Visual Studio te va a encantar perder todas esas funciones a las que estás acostumbrado. Se puede ejecutar en cualquier sitio siempre que tengan el navegador adecuado y no es el caso en muchas empresas grandes. Y una gran comunidad de fans à la Apple.

¿Me gusta JavaScript?

¿Me gusta una tecnología que, si tenemos suerte, solventará dentro de cinco años todos los problemas que resolvimos hace ocho años con Silverlight?

Probablemente cuando tanto la tecnología como yo hayamos madurado.

Por supuesto que me gusta, yo quiero ser guay...


También aprendí a amar WPF pero no me costó tanto tiempo.

No hay comentarios:

miércoles, 10 de junio de 2015

¿Por qué Windows 10 marcará la diferencia?

¿Te acuerdas de cuando tenías que ir a casa de tu vecino para que te prestase su cinta del Zanac?

¿Te acuerdas cuando te compraste el casette de doble pletina para copiar el juego? como copia de seguridad y para hacer testing, claro

Entoces llegaron los discos flexibles de 5 1/4 comparados con el cassette eran rapidísimos y su capacidad increible, pero no cambiaron el hecho de que tuvieses que ir a casa de tu amigo para conseguirte una copia del Alley Cat.

Entonces llegó internet y ... todavía tuviste que ir a casa de tu amigo para que te prestase el diskette del Ishar porque se tardaba bastante menos tiempo en ir andando a la otra punta del planeta que en descargar 1MB.

Pero internet marcó la diferencia. Después de algún tiempo pudiste olvidarte completamente de los diskettes de 3.5 y solo tenías que visitar a tu amigo para que te prestase el CD del Dungeon Keeper II o algo así.

Y algún tiempo más tarde (hoy) te puedes incluso descargar una máquina virtual de 60GB en minutos. parece que en el momento en el que hubo buen ancho de banda dejé de disfrutar con los ordenadores...

Windows 10 es similar cuando se trata de cambiar el paradigma de la distribución de software y explicaré por qué.


La mayoría de los programas y juegos para ordenadores de escritorio fueron creados para Windows y no para Linux ni Mac y hay una buena razón para ello. La cuota de mercado del escritorio Windows hacía que trabajar para otras plataformas fuese tirar el dinero.

Los app stores llegaron y, en lugar de irte a la peligrosa internet a descargar los programas, te irías a un entorno supervisado desde donde podrías descargarte tus programas de manera segura.

PERO

De los ordenadores de escritorio tan solo un "ridículo" 16.45% (W8 + 8.1) puede ejecutar aplicaciones de la Microsoft Store mientras que la gran mayoría de los ordenadores (W7 + XP) un 72.36% están todavía anclados en el paradigma antiguo. (fuente)

Y nos hacemos la pregunta otra vez. ¿Por qué desarrollar una aplicación para el 16% de los ordenadores cuando podemos crear la misma aplicación por el mismo dinero para el 89% (dado que W8 y 8.1 son compatibles con el viejo código de escritorio)? La respuesta es obvia.

Y aquí viene Windows 10.

Ofreciendo Windows 10 como una actualización gratuita Microsoft va a convencer probablemente a la mayoría de usuarios de W7, 8 y 8.1 de instalar la última versión del sistema operativo y, con ella, la capacidad de ser clientes de la Tienda Microsoft.

No solo eso. Dado que las aplicaciones de Windows 10 también van a funcionar en cualquier hardware que sea capaz de ejecutar W10 el público objetivo no va a ser solo aumentado si no, posiblemente multiplicado.

Podrás desarrollar una vez tu aplicación y ésta podrá ser descargada por los usuarios de escritorio y tambien por los usuarios de Windows Phone y por los de XBox y por los de RaspberryPI y por los de las Hololens!.


Microsoft estima que en un par de años habrá mil millones de dispositivos W10 en el mundo y una vez más la pregunta será:

¿Por qué querría nadie desarrollar para otra plataforma?

No hay comentarios:

miércoles, 11 de febrero de 2015

Se acabaron las funciones recursivas para definir CAML Queries gracias a Camlex

Algunas veces tienes un número aleatorio de condiciones para incluir en una CAML query y en esos casos yo solía definir las consultas usando una función recursiva que normalmente tenía que debugar unas cuantas veces me funciona siempre a la primera.

El código para este tipo de consultas sería algo así (y este es de los simples):

public List<string> GetSomeInfo(string fieldsToSearch, string contentTypesToSearch)
{
    ...

    var queryval = string.Empty;
    if (contentTypesToSearch.IsNullOrEmpty())
        queryval = string.Format("<Where>" + GenerateFieldsQuery(fieldsToSearch.Split(','), 0) + "</Where>", text);
    else
        queryval = string.Format("<Where><And>" + GenerateCTypesQuery(contentTypesToSearch.Split(','), 0) + GenerateFieldsQuery(fieldsToSearch.Split(','), 0) + "</And></Where>", text);

    var scope = "Scope=\"RecursiveAll\"";

    ...
}

private static string GenerateFieldsQuery(string[] fields, int index)
{
    if (fields.Length == 0) return string.Empty;

    if (fields.Length == index + 1)
        return "<Contains><FieldRef Name='" + fields[index] + "' /><Value Type='Text'>{0}</Value></Contains>";

    return "<Or><Contains><FieldRef Name='" + fields[index] + "' /><Value Type='Text'>{0}</Value></Contains>" + GenerateFieldsQuery(fields, ++index) + "</Or>";
}

private static string GenerateCTypesQuery(string[] cTypes, int index)
{
    if (cTypes.Length == 0) return string.Empty;

    if (cTypes.Length == index + 1)
        return "<Eq><FieldRef Name='ContentType' /><Value Type='Choice'>" + cTypes[index] + "</Value></Eq>";

    return "<Or><Eq><FieldRef Name='ContentType' /><Value Type='Choice'>" + cTypes[index] + "</Value></Eq>" + GenerateCTypesQuery(cTypes, ++index) + "</Or>";
}

Eso era hasta ahora... gracias a Camlex (y gracias a Luis por decírmelo), este código se puede escribir así:

public List<string> GetSomeInfo(string fieldsToSearch, string contentTypesToSearch)
{
    ...

    var queryVal = string.Empty;
    var fieldExtensions = new List<Expression<Func<SPListItem, bool>>>();
    var cTypeExtensions = new List<Expression<Func<SPListItem, bool>>>();

    if (!contentTypesToSearch.IsNullOrEmpty())
    {
        foreach (var cType in contentTypesToSearch.Split(','))
            cTypeExtensions.Add(x => (string)x["ContentType"] == cType);
    }

    foreach (var field in fieldsToSearch.Split(','))
        fieldExtensions.Add(x => ((string)x[field]).Contains(text));

    var expressions = new List<Expression<Func<SPListItem, bool>>>();
    expressions.Add(ExpressionsHelper.CombineOr(cTypeExtensions));
    expressions.Add(ExpressionsHelper.CombineOr(fieldExtensions));

    queryVal = Camlex.Query().WhereAll(expressions).ToString();

    ...
}

Echaré de menos los métodos recursivos... me hacían sentir especial...

No hay comentarios:

jueves, 23 de octubre de 2014

Surface 3 WiFi e Hyper V


Parece que algo no es completamente compatible entre Hyper V y la Surface

Y si has instalado la ultima versión de Visual Studio probablemente habrás notado que tarda más de la cuenta en conectarse al Wi-Fi Por no mencionar que el modo Sleep ha desaparecido...

Para evitar este problema he creado un par de accesos directos en el escritorio, uno para apagar Hyper V y otro para encenderlo cuando de verdad haga falta.

Bastante simple:
Click derecho en el escritorio y seleccionas Nuevo > Acceso Directo
Se abrirá la pantalla para seleccionar el programa al que apunta el acceso directo.

Seleccionamos bcdedit.exe en la carpeta system32.


 
Y finalmente le ponemos un nombre.

Ahora la parte complicada. Hacemos click derecho en el acceso directo que hemos creado y seleccionamos Propiedades.


Para el acceso directo de HyperV On necesitarás este texto en el TextBox Target:
C:\Windows\System32\bcdedit.exe /set hypervisorlaunchtype auto
Para el HyperV Off necesitarás este otro:
C:\Windows\System32\bcdedit.exe /set hypervisorlaunchtype off
Después de hacer este cambio haz click en Popiedades Avanzadas y selecciona Ejecutar como Administrador.



Y por último selecciona un icono bonito para el acceso directo:


Recuerda hacer los accesos directos para HyperV On e HyperV Off.


Y por último recuerda que después de ejecutar estos accesos directos tendrás que reiniciar la máquina para que los cambios tengan efecto.

No hay comentarios:

miércoles, 27 de agosto de 2014

No puedo entrar en mi VM de Azure (y de cómo solucionarlo)

Estaba yo creando una regla nueva en el firewall de una de mis VMs de azure y se me fue un pelín la mano a la hora de bloquear IPs... y bloqueé TODO el tráfico.

¿Qué hacer?

  • Mi primer pensamiento fue bajarme la máquina, hacer el cambio en local y subirla otra vez... pero son 250GB.
  • Intenté cambiar la regla del firewall por powershell desde la suscripción de azure pero el Get-AzureWinRMUri no funcionaba.
  • Finalmente, tras preguntar a un amigo que le preguntó a un amigo suyo me dijeron que podía editar el registro de un disco de sistema operativo windows desde otro windows. ¡Increible! ¡Esa era la respuesta!


De hecho, una vez que sabía qué hacer, encontré un post muy detallado sobre cómo hacerlo.

Así que borré mi amada máquina virtual, adjunté el VHD de SO a otra máquina y desde el editor de registro borré la regla del firewall que estaba bloqueando todo el tráfico.

Entonces desconecté el VHD, me creé una máquina nueva con él y listo. Ya teníamos la máquina funcionando y accesible.

No hay comentarios:

martes, 29 de julio de 2014

Snapshots en Máquinas Virtuales de Azure más fáciles todavía

He estado pensando en hacer y restaurar snapshots de mis máquinas virtuales de Azure un montón de tiempo pero nunca he tenido tiempo para hacerlo... hasta hoy.

Es muy facil cuando sabes cómo hacerlo pero puede ser un poco lioso cuando tienes que empezar desde cero y como tengo que escribir un post explicándolo y hace mil años que no posteaba aquí he pensado que sería buena idea hacerlo en mi blog.

Empecemos por el principio:



Con un poco de suerte ya lo tendrás funcionando.
Ahora al grano. Chris Clayton ha creado un paquete de scripts que funcionan maravillosamente para administrar screenshots de MV de azure que son los que yo estoy usando ahora. Si eres demasiado flojo como para ir a su página también puedes descargarte los scripts de aquí.

Lo único que necesitas configurar es el fichero Subscriptions.csv. Es un fuchero CSV por lo que en la primera línea tienes los nombres de las columnas y en las siguientes los datos de las suscripciones que quieras configurar. Tiene esta pinta:
SubscriptionName,SubscriptionId,CertificateThumbprint
"IT","XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Este fichero nos ayudará a ejecutar los comandos más fácilmente ya que contiene toda la información de las suscripciones que vamos a usar. Si, vale, pero... ¿De dónde saco los datos? Mira.

Primero, para obtener toda la información sobr nuestra suscripción podemos correr en PowerShell esto:
Get-AzureSubscription
Y obtendremos una pantalla como esta:
Esos son los parametros que necesitas rellenar. Fácil.

Por último para correr los comandos necesitarás dar datos sobre qué suscripción usar y sobre qué máquina virtual dentro de esa suscripción. Para ello puedes ver la lista de MVs ejecutando Get-AzureVM. Te saldrá una pantalla como esta:


Ahora tenemos todos los parámetros que necesitamos. Podemos lanzar, a modo de prueba, el script para ver la lista de snapshots que tenemos tomados de una máquina:


./GetSnapshotList.ps1 -subscriptionName "NombreDeLaSuscripción" -cloudServiceName "NombreDelServicio" -virtualMachineName "Nombre" -maximumDays 15
Where:
  • -subscriptionName es el SubscriptionName que obtuviste de Get-AzureSubscription y escribiste luego en el fichero Subscriptions.csv
  • -cloudServiceNameeste es la columna ServiceName que puedes ver en Get-AzureVM
  • -virtualMachineName  es la columna Name que puedes ver en Get-AzureVM

Y eso es todo.

Cosas para recordar:
  • La máquina virtual debe de estar apagada antes de tomar el snapshot (hay un parametro para eso en el comando de PowerShell)
  • Los datos en tus discos "Temporary Storage" no se van a salvar ni a restaurar porque son temporales. Sí, yo ya sabía que iba a funcionar de esta forma, pero no pude resistirme a probar.

Para terminar de probarlo todo hice un snapshot de una de mis máquinas de desarrollo de SharePoint, luego hice algunos cambios en ella, después restauré el snapshot y los cambios se deshicieron, exactamente como era de esperar. Y además fué más rápido de lo que yo esperaba.

No hay comentarios:

viernes, 8 de noviembre de 2013

Windows Store y precios

Aprovechando que van a unificar y rebajar el precio de las licencias de Windows Store os cuento mi experiencia.

Por un lado creo que debería de ser gratis publicar apps, algo como lo que pasa en internet. Tu publicas y la gente decide si les gusta o no.

Por otro lado también entiendo que hace falta un control de calidad antes de permitir la entrada de apps en la store y eso cuesta dinero.

Hay otros que dicen que si fuera gratis todo el mundo subiría una porquería, ahí también difiero... Hay quien sube una porquería por no tirar el dinero... Yo sin ir más lejos.

Tuve una idea para dos apps hace un año, me saqué la licencia por 60€ pero me falló el diseñador y yo estoy siempre bastante liado así que no hice nada. Finalmente un mes antes de que me caducase me dije "¡Necesitas subir por lo menos una!" y así lo hice.

Hice el MorseCentral en un par de mañanas de sábado y la subí. Ya puedo decir que tengo una App en la store y que "no desperdicié" la licencia pero en realidad mi App de 6 horas de trabajo no ha servido para mejorar la store, más bien al contrario. Como toda App de 6h hecha por un novato tiene fallos técnicos y de usabilidad por no hablar del diseño que es una catástrofe.

En conclusión. Opino que si quieren que haya muchas apps que pongan gratis la licencia de desarrollo. Democracia al poder. Y siquieren que la store no se llene de mierda pues que hagan que las apps con menos de, digamos ¿100 descargas? y ninguna actualización en el último año se borren automáticamente.

Hey, al menos no he tirado 60€ por la alcantarilla. He entretenido a 60 desconocidos durante un par de segundos de su vida y entretenerlos solo me ha costado 1€ por persona :)

No hay comentarios:

jueves, 19 de septiembre de 2013

¿Qué campos hay disponibles en un SPListItem?

Cuando traes los elementos usando una consulta CAML con el parámetro ViewFields configurado no hay manera (o al menos yo no la conozco) de encontrar qué campos tienes disponibles y con datos.

La forma estandar de coger la lista de campos del tipo de contenido no vale porque el ContentType es null en esta clase de elementos…

La forma más fácil para ver qué tenemos es mirar en el XML del elemento.

static List<string> ExcludedFields = new List<string> { "z", "ows_ServerRedirected", "ows_FileRef", "ows_PermMask", "ows_FSObjType", "ows__Level", "ows__ModerationStatus" };
/// <summary>
/// Gets a dictionary with the available fields and its values.
/// </summary>
public static Dictionary<string, string> getAvailableFields(this SPListItem item)
{
    XElement row = XElement.Parse(item.Xml);
    Dictionary<string, string> Fields = new Dictionary<string, string>();

    foreach (XAttribute field in row.Attributes())
    {
        if (!ExcludedFields.Contains(field.Name.LocalName))
            Fields.Add(field.Name.LocalName.Substring(4), field.Value);
    }

    return Fields;
}

Usando esto he logrado reducir el tráfico que generaba un método de un web service en un 65%.

No hay comentarios:

¿Cuánto estás trayendote desde SharePoint en tus consultas CAML?

Yo no se tú, pero yo me estoy trayendo más de la cuenta.

Esta es una de esas cosas que no notas hasta que es demasiado tarde. Yo creía que sólo con añadir filtros estrictos a mis consultas CAML para traer estrictamente los elementos que necesitaba era suficiente pero hay algo más que puedes hacer.

Puedes restringir los campos que te estás trayendo... y debes.

La consulta SQL que SharePoint genera para traerse los elementos cuando dejas el parámetro ViewFields de la CAML vacío casi duplica la complejidad de la consulta que se genera cuando especificas los campos que quieres usar o usas una vista.

Dos simples líneas como estas:

query.ViewFields = "<FieldRef Name=\"Value\" />";
query.ViewFieldsOnly = true;
Pueden hacer tu query mejor.

¿Quién podría resistirse cuando es así de simple?

No hay comentarios:

viernes, 23 de agosto de 2013

Scopes en una consulta CAML

He estado trabajando bastante tiempo con CAML queries y el scope, también conocido como ámbito, es siempre algo muy importante a tener en cuenta. ¿Cuántas veces mis consultas no devuelven nada cuando estoy seguro de que deberían tener resultados…

Básicamente tenemos dos modificadores Recursive y All y nada, ¿Podemos llamar a "nada" un modificador? All va a devolver ficheros y carpetas. Recursive repetirá la query en todas las carpetas bajo la que hemos establecido como raíz para la consulta.

Si no pones el scope a All solo traerás ficheros. Si no lo pones a Recursive solo traeras elementos de la carpeta en la que estás trabajando. No hay tantas posibilidades por lo que voy a hacer un ejemplo de cada una.

Vamos a imaginar que tenemos una carpeta de SharePoint como esta y que vamos a lanzar consultas contra ella:

CamlScopeTreeSample

Ya se que no soy bueno con el paint pero lo que quiero mostrar aquí es un arbol en donde tenemos una carpeta que será la raíz de las queries que lancemos(Root), dos sub carpetas y algunos ficheros. Para cada posible caso resaltaré los elementos que puedes esperar recibir de la query.

Antes de empezar te recuerdo que el scope se selecciona en la propiedad ViewAttributes del objeto SPQuery.

Para que quede todavía más claro he pintado los niveles:

CamlScopeTreeSampleLevels

La línea verde mara lo que está dentro de la carpeta raíz, la azul lo que esta dentro de SubFolder1 y la roja el contenido de SubFolder2.

ViewAttributes dejado por defecto:

CamlScopeByDefault
Esto traerá solo los ficheros de la carpeta raíz.

ViewAttributes = "Scope='Recursive'"

CamlScopeRecursive

Esto traerá todos los ficheros de todas las carpetas.

ViewAttributes = "Scope='All'"

CamlScopeAll

Esto devolverá ficheros y carpetas bajo la raíz.

ViewAttributes = "Scope='RecursiveAll'"


CamlScopeRecursiveAll

Y finalmente con RecursiveAll puedes traerte todo lo que hay dentro de la carpeta raíz.

Buena suerte con las consultas.

No hay comentarios:

lunes, 19 de agosto de 2013

El modelo de objetos de cliente es fantástico

Esta es una de esas cosas que sabes que están ahí pero que nunca usas porque ya sabes cuarenta maneras diferentes de hacerlo.

Tan solo cuatro años después de haber empezado a trabajar con SharePoint 2010 pensé "¿Por qué no darle una oportunidad al Modelo de Objetos de Cliente de SharePoint?" en realidad lo que pasó es que tuve un requerimiento de un cliente y debo decir que estoy MUY impresionado. La simplicidad, la velocidad y la predecibilidad son buenísimas, para los estádares a los que estamos acostumbrados.

Aunque el MOC (o COM) es muy bueno me he creado unos cuantos metodos y extensiones que me ayudan a manejar las situaciones más comunes. Algunas son las mismas que uso en el modelo de objetos de SharePoint pero traducidas a COM y otras son nuevas, vamos a empezar:

Es muy fácil conectar usando autenticación windows o basada en formularios. Más sencillo que ninguna otra cosa que haya visto hasta la fecha.

public static ClientContext GenerateClientContextWinAuth(string URL)
{
    return new ClientContext(URL);
}

public static ClientContext GenerateClientContextFBAAuth(string URL, string userName, string password)
{
    ClientContext ctx = new ClientContext(URL);
    ctx.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
    ctx.FormsAuthenticationLoginInfo = new FormsAuthenticationLoginInfo(userName, password);

    return ctx;
}


Windows auth 1 linea de código FBA 3. Bien.

¿Te acuerdas de como era leer y escribir ficheros de SharePoint? Pue mira qué fácil es con el modelo de objetos de cliente.

public static string ReadFile(ClientContext Context, string ListName, string FileName)
{
    List StorageList = Context.Web.Lists.GetByTitle(ListName);
    string SharePointFilePath = GetFilePathInSharePoint(Context, StorageList, FileName);

    FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(Context, SharePointFilePath);

    using (fileInfo.Stream)
    {
        using (StreamReader sr = new StreamReader(fileInfo.Stream))
        {
            return sr.ReadToEnd();
        }
    }
}

public static void WriteFile(ClientContext Context, string LocalFilePath, string ListName, string SPFileName)
{
    List StorageList = Context.Web.Lists.GetByTitle(ListName);

    string SharePointFilePath = GetFilePathInSharePoint(Context, StorageList, SPFileName);

    using (FileStream fs = new FileStream(LocalFilePath, FileMode.Open))
        Microsoft.SharePoint.Client.File.SaveBinaryDirect(Context, SharePointFilePath, fs, true);
}

private static string GetFilePathInSharePoint(ClientContext ctx, List StorageList, string FileName)
{
    if (StorageList.RootFolder.ServerObjectIsNull != false)
    {
        ctx.Load(StorageList.RootFolder);
        ctx.ExecuteQuery();
    }

    string ListRootFolderURLDocuments = StorageList.RootFolder.ServerRelativeUrl;
    return Path.Combine(ListRootFolderURLDocuments, FileName);
}


Quitando la funcioncita para encontrar la url del elemento en la biblioteca de documentos más fácil imposible.

También me he creado un par de métodos para facilitar el trabajo con el StratexFramework.

Si estás desarrollando un programa y quieres usar algo de este código perfecto y si no pues puedes modificarlo para que se adecúe a tu entorno. Aquí hay un método para traerse la entidad raíz del framework:

public static ListItem GetRootEntity(this List ComList)
{
    CamlQuery camlQuery = new CamlQuery();
    camlQuery.ViewXml = string.Format(@"<View>
                                            <Query>
                                                <Where>
                                                    <Eq>
                                                        <FieldRef Name='ContentType'/>
                                                        <Value Type='Choice'>Entity</Value>
                                                    </Eq>
                                                </Where>
                                                <RowLimit>1</RowLimit>
                                            </Query>
                                        </View>");

    ListItemCollection items = ComList.GetItemsExecuted(camlQuery);

    if (items.Count == 1)
        return items[0];
    else
        return null;
}

Bonito y fácil.

La query es un pelín distinta de la que usamos siempre en el SPQuery pero aún así bastante similar.

Después me he creado un método que te ayudará cuando quieras hacer una query dentro de una carpeta sin importarte el resto del framework. Primero voy a poner el helper y luego la aplicación para que veáis como lo utilizo:

public static CamlQuery CreatePositionedQuery(this ListItem StartEntity)
{
    CamlQuery camlQuery = new CamlQuery();
    camlQuery.ViewXml = string.Format(@"<View Scope='RecursiveAll' >
                                            <Query>
                                                <Where>
                                                    <And>
                                                        <Eq><FieldRef Name='FileDirRef' /><Value Type='Text'>{0}</Value></Eq>
                                                        {1}
                                                    </And>
                                                </Where>
                                            </Query>
                                        </View>", GetChildrenFolder(StartEntity), "{0}"); //This is the folder url and the placeholder for the real query.


    return camlQuery;

}

private static string GetChildrenFolder(ListItem startItem)
{
    startItem.InitializeIfNeeded("FileDirRef");
    startItem.InitializeIfNeeded("FileLeafRef");

    return startItem["FileDirRef"] + "/" + startItem["FileLeafRef"];
}

Con esto, básicamente le decimos a SharePoint que ejecute la query debajo de la carpeta del elemento que le estamos pasando como parámetro. Y de esta manera podemos posicionar fácilmente nuestras consultas en el arbol de carpetas.

Antes que nada, una función para traer todas las entidades hijas que están debajo de una entidad dada y luego otra función para traer un elemento con un nombre dado bajo una carpeta dada:

public static ListItemCollection GetChildEntities(ListItem StartEntity)
{
    List ComList = StartEntity.ParentList;

    CamlQuery camlQuery = CreatePositionedQuery(StartEntity);
    camlQuery.ViewXml = string.Format(camlQuery.ViewXml,
                                    @"<And>
                                        <Eq><FieldRef Name='State' /><Value Type='Choice'>Live</Value></Eq>
                                        <Eq><FieldRef Name='ContentType' /><Value Type='Choice'>Entity</Value></Eq>
                                        </And>");

    return ComList.GetItemsExecuted(camlQuery);
}

public static ListItem GetChildItem(this ListItem StartEntity, string Title)
{
    List ComList = StartEntity.ParentList;

    CamlQuery camlQuery = CreatePositionedQuery(StartEntity);
    camlQuery.ViewXml = string.Format(camlQuery.ViewXml,
                                    string.Format("<Eq><FieldRef Name='Title' /><Value Type='Text'>{0}</Value></Eq>", Title));

    ListItemCollection result = ComList.GetItemsExecuted(camlQuery);

    if (result.Count > 0)
        return result[0];
    else
        return null;
}
Crear un elemento nuevo e también muy fácil. Lo más complicado es decidir si el elemento es carpeta u hoja:
public static ListItem CreateItemUnder(this ListItem ParentItem, string Title, string ContentType, bool isLeaf)
{
    ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
    itemCreateInfo.FolderUrl = GetChildrenFolder(ParentItem);
    itemCreateInfo.LeafName = Title;

    if (isLeaf)
        itemCreateInfo.UnderlyingObjectType = FileSystemObjectType.File;
    else
        itemCreateInfo.UnderlyingObjectType = FileSystemObjectType.Folder;

    ListItem NewItem = ParentItem.ParentList.AddItem(itemCreateInfo);

    if (ContentType != null)
        NewItem["ContentTypeId"] = GetContentType(ParentItem.ParentList, ContentType).Id;

    return NewItem;
}
Un pequeño atajo para ejecutar consultas:
public static ListItemCollection GetItemsExecuted(this List listToQuery, CamlQuery query)
{
    ListItemCollection childItems = listToQuery.GetItems(query);

    listToQuery.Context.Load(listToQuery);
    listToQuery.Context.Load(childItems);
    listToQuery.Context.ExecuteQuery();

    return childItems;
}
En algunos casos el campo que quieres leer no viene en la ejecución de la query quizá porque hass sido una mijita más restrictivo de la cuenta con el parametro viewfields... Puedes probar este truco:
public static void InitializeIfNeeded(this ListItem item, string InternalName)
{
    if (!item.FieldValues.ContainsKey(InternalName))
    {
        item.Context.Load(item);
        item.Context.ExecuteQuery();
    }
}

¿Estás intentando conseguir un tipo de contenido de una lista? Fácil.


public static ContentType GetContentType(List list, string cTypeName)
{
    list.Context.Load(list.ContentTypes);
    list.Context.ExecuteQuery();

    foreach (ContentType ctype in list.ContentTypes)
    {
        if (ctype.Name == cTypeName) return ctype;
    }

    return null;
}

¿Quieres guardar un SPFieldUserValue en un SPFieldUser usando el modelo de objetos de cliente o necesitas leerlo desde allí? Complicado. Yo diría que innecesariamente complicado, pero tengo un último truco:

public static string UserToString(object fieldUserValue)
{
    if (fieldUserValue == null) return string.Empty;

    FieldUserValue user = fieldUserValue as FieldUserValue;

    return string.Format("{0};{1}", user.LookupId, user.LookupValue);
}

public static FieldUserValue StringToUser(object fieldUserValueString)
{
    FieldUserValue user = new FieldUserValue();

    if (string.IsNullOrEmpty(fieldUserValueString.ToStringSafe())) return user;

    string[] tokens = fieldUserValueString.ToStringSafe().Split(';');

    user.LookupId = tokens[0].ToNullableInt() ?? 0;

    return user;
}

El modelo de objetos de cliente me ha parecido potente y muy facil de usar. Te aconsejo que lo uses, si no lo haces ya.

No hay comentarios:

jueves, 25 de abril de 2013

Necesitamos desarrolladores

StratexSystems está creciendo y hemos pensado en crear una sucursal en España. Nuestro primer objetivo es contratar a dos o tres desarrolladores de SharePoint que sean capaces de depurar, mejorar y ampliar StratexPoint, que es una solución de RBPM completamente creada en SharePoint.

Tenemos clientes muy interesantes en el mundo financiero que necesitan software de la mejor calidad y necesitamos a gente que sea buena en SharePoint y que además tenga interés por aprender y utilizar nuevas tecnologías. Actualmente ya tenemos una aplicación para Windows 8 que estamos deseando de mejorar, un par de servicios en Azure y planes para construir un portal en HTML5 además de estar estudiando un cambio de plataforma a SharePoint 2013.

No importa en qué parte de España estés siempre y cuando tengas un buen nivel de inglés. Vamos a tener la mitad del equipo en España y la otra mitad en Londres por lo que las reuniones serán mayoritariamente en inglés.

Si eres un desarrollador de SharePoint con experiencia y buscas nuevos retos mándanos tu cv.

Puedes ver la oferta de trabajo aquí.

No hay comentarios:

martes, 23 de abril de 2013

Desayuno para Ejecutivos de StratexSystems en Londres

En la primera reunión para ejecutivos del 2013, StratexSystems invitó a dos de sus clientes a compartir sus experiencias en las diferentes etapas del viaje que representa la gestión del riesgo institucional (Enterprise Risk Management).

+Andrew Smart hizo una pequeña demostración a los asistentes de StratexPoint y la metodología de gestión de riesgo institucional basada en el rendimiento (Risk Based Performance Management) además de presentar a Gillian y a Kevin que también participaron.

Para los que os preguntéis en qué trabajo, aquí tenéis una muestra:

 

La primera presentación, por parte de los invitados, fue un caso de estudio de uno de los bancos más nuevos y de más rápido crecimiento en el Reino Unido  (Aldermore Plc).

De la mano de su Jefe de Riesgo Operacional, Kevin Pearce, este caso de estudio cuenta la historia de una organización que se encuentra en una fase relativamente temprana del camino del ERM.

Kevin nos contará algunos trucos sobre cómo establecer una agenda de ERM y como hacerla relevante en una organización de rápido crecimiento enfocada a dar mucho valor tanto a los clientes como a los accionistas.

 

La segunda presentación es un caso de estudio de la empresa contratista de sercicios financieros más grande del Reino Unido (HML) y fue conducida por la Directora de Gestión de Riesgo Empresarial, Gillian Weatherill.

En esta charla, Gillian comparte con nosotros su experiencia de más de cinco años en el camino del ERM y cómo consiguieron reducir un 60% sus pérdidas operativas y un 23% sus provisiones de capital en 18 meses.

 

Puedes encontrar más información sobre Reuniones de Ejecutivos, Webinars y soluciones de software en http://www.stratexsystems.com

¡Muchas gracias Gillian y Kevin!

Buen video James.

No hay comentarios:

lunes, 22 de abril de 2013

Editando SPListItems desde SPWeb.GetSiteData

En mi solución tengo un número desconocido de subsitios que contienen un número desconocido de SPListItems que necesitan ser actualizados. Parece la manera perfecta de probar el  GetSiteData.

La documentación es útil y podrás probar las consultas sin problemas ¿De verdad? Síp la documentación está bien pero este método trae de vuelta un objeto DataTable y yo lo que necesito es actualizar los SPListItems.

Bueno, si miras al DataTable verás que tienes todo lo necesario para traerte el SPListItem fácilmente.

Me he creado un extension method, bueno dos,... Me encantan los extension methods.
public static SPListItem GetListItemFromSiteData(this DataRow ItemRow, SPSite ParentSite)
{
    using (SPWeb Web = ItemRow.GetWebSiteData(ParentSite))
    {
        return Web.Lists[new Guid(ItemRow["ListId"].ToString())].GetItemById(Convert.ToInt32(ItemRow["ID"]));
    }
}

public static SPWeb GetWebSiteData(this DataRow ItemRow, SPSite ParentSite)
{
    return ParentSite.OpenWeb(new Guid(ItemRow["WebId"].ToString()));
}

Usando estos dos podrás iterar fácilmente por la colección de filas del DataTable, seleccionar qué elementos necesitan ser actualizados y actualizarlos.

No he probado cómo de rápido es comparado con traerte los objetos con una CAML query. No tener que crear la SPListItemCollection podría hacer este método más rápido y más conveniente para según que cosas... Lo probaré,

No hay comentarios:

domingo, 21 de abril de 2013

Batería y Tiles de Acceso Directo para WP8


Como posiblemente sabrás conseguí mi WP8 hace un par de semanas. Una de las cosas que me molesta es tener que ir a Configuración>LoQueSea>LoQueQuieres y lo suelo hacer un par de veces al día, todos los días. Eso quiere decir que me molesta 730 veces al año...

Genial! pensé. Voy a hacer una aplicación con tiles de accesos directos y por fin voy a tener una app en el marketplace que sea útil, una que tenga sentido.

Mientras me descargaba la SDK pensé que podría estar bien tener una aplicación que me dijese el nivel de la batería en una tile "Alguien debe haber hecho esto ya, iré al marketplace y pillaré alguna" Y tenía razón.

En el marketplace encontré Battery, una estupenda aplicación que muestra una gráfica con el nivel de la batería, tiene estadísticas sobre todo lo imaginable, te dice el nivel de carga y hasta te da una estimación del número de horas restantes hasta la próxima carga. ¡Excelente app! ¡este tío ha pensado en todo! pero... ¿Qué es eso? Oh, otra vez no... Sí, tiles de acceso directo.

La aplicación proporciona un juego de tiles de acceso directo y funcionan perfectamente. WiFi, Localización, Bluetooth, Modo vuelo y Red Movil. Y mi plan era crear accesos directos para el WiFi y el Modo Vuelo solamente...

Obviamente no voy a hacer la app para los accesos directos, ya hay un montón en el marketplace. Pero si lees este post y tienes un WP8 prueba esta app. Te ayuda a trabajar más rápido con el teléfono y, en mi opinión, las tiles lo hacen parecer más geek. Ahora me gusta usar estas tiles de accesos directos y eso me hace feliz 730 veces al año.


¿Se me ocurrirá alguna vez una idea para una app?.

No hay comentarios:

¿Cursos de Universidad Gratis? Coursera


Edicación gratis. Mejor imposible.

Escuché hablar sobre estos cursos hace cosa de un mes y me ha apuntado a dos. El primero empieza el lunes que viene así que no puedo decir si son buenos o si valen la pena todavía pero tienen muy buena pinta.

Me he apuntado a un curso de inteligencia artificial y otro de programación.

La inteligencia artificial es un campo que me llama mucho la atención y en el que no tengo ninguna clase de experiencia. ¿No sería bonito poder ponerle un poco de inteligencia a cualquier cosa en la que estés trabajando? Creo que podría dar valor añadido a a alguna cosa, y si no pues por lo menos he satisfecho mi curiosidad.

Y el curso de programación también es interesante, si las cosas han cambiado en los últimos 10 años quiero saberlo y si no, quiero recordar como eran :)

Antes de apuntarme a más cursos voy a intentar acabar con estos dos, pero ya tengo el ojo echado a otro curso de arquitecturas orientadas a patrones para software concurrente...

¿Por qué no te apuntas conmigo en https://www.coursera.org?

No hay comentarios:

viernes, 19 de abril de 2013

Necesitamos un Día del Orgullo Programador

Cada vez que estoy buscando un desarrollador senior es lo mismo.

Parece que si has sido programador cuatro años ya no puedes seguir programando. Ahora tienes que ser jefe de equipo o jefe de desarrolladores o un consultor preventa y cualquier cosa menos que eso es una vergüenza para tu carrera. ¿Por qué un programador es menos que un jefe de equipo? ¿Me lo puede explicar alguien?

¿Cómo puede alguien después de cuatro años decir que tiene tanta experiencia que ya no quiere programar más?

Recuerdo una vez que estaba contratando un desarrollador en Madrid y un chaval buscando su primer empleo después de terminar la universidad me dijo que él no iba a programar porque él era ingeniero. Me quedé perplejo... Yo fui a la universidad precisamente para aprender a programar bien...

Para mí es como si a un futbolista no quisiera aprender a jugar al futbol porque lo que él quiere es ser entrenador.

¿Cómo piensas que vas a ser capaz de decirle a la gente qué hacer y cómo hacerlo si tú mismo no sabes porque nunca te has preocupado por aprender?

Los managers hacen falta pero me parece que la gente piensa que un desarrollador es un subproducto de un manager.

Déjame decirte algo, un desarrollador no es un tío que no valía para nada más y se tuvo que conformar con ser ignorado en una esquina de una oficina en medio de ninguna parte. Ser un desarrollador es más difícil de lo que la mayoría de la gente se piensa.

En mi caso he sido programador durante siete años, esto solo profesionalmente. He estado programando desde que tenía 9 años y me compraron mi MSX HB-20P y después de todo este tiempo me siento como si solo hubiese arañado la superficie de lo que es el desarrollo.

He visto trabajar a buenos desarrolladores y realmente marcan la diferencia. La cantidad de conocimientos que tienen es sobrecogedora igual que la claridad de sus pensamientos y la elegancia del código que hacen.

Son artistas y una clase muy impresionante de artistas. Ellos entregan diariamente, controlan la presión y superan un número infinito de problemas aprendiendo de ellos y mejorando su código y su entorno para asegurarse de que no van a tener esos problemas nunca más (ni ellos ni ninguno de los del equipo)

Los Grandes desarrolladores son generosos con su conocimiento, pregúntales sobre lo que hacen y seguramente te sentirás abrumado por la cantidad de detalles y trucos que te darán. Ellos no esconden lo que saben, les encanta compartir. Hay tanto que aprender y tan poco tiempo.

No se coge esa clase de experiencia en un par de años, cuesta toda una vida de esfuerzo convertirse en un verdadero experto en este campo. Y si no cambiamos nuestro modo de ver lo que es un desarrollador la cantidad de buenos desarrolladores que tendremos en el futuro será ridícula.

Si eres un programador siéntete orgulloso de lo que haces. Un ingeniero con infinitas piezas para elegir. Un general con infinitos soldados haciendo exactamente lo que tú les dices. Eres el hacedor.

Los desarrolladores necesitamos mejorar la manera en la que nos vemos a nosotros mismos, necesitamos cambiar la manera en que las empresas nos ven.

Necesitamos un Día del Orgullo Programador.

Si te encanta aprender nuevos trucos, si te encanta cuando una clase hace exactamente lo que quieres y la belleza de la forma en que la hiciste. Si te encanta mejorar el código en cada iteración o si eres capaz de cambiar un método, mejorarlo en un orden de magnitud, y sentirte el tío más feliz. Si te encanta programar... No cambies.

Necesitamos que seas un desarrollador. El mundo necesita que te conviertas en un Gran desarrollador. El mundo necesita que tú lo mejores.

Y eso lleva tiempo.

No hay comentarios:

jueves, 18 de abril de 2013

Patrón Recoge Tu Cuarto Después de Jugar

¿Es esto un patrón?

En la mayoría de los casos quieres cambiar el valor de una variable y dejarla así pero en algunas ocasiones quieres cambiar el valor de la variable, hacer algo y ponerla como estaba.

Con este código es muy fácil y te aseguras de que no te vas a olvidar nunca.

La idea es crear una clase que implemente la interfaz IDisposable y guarde los valores en el estado en el que estaban cuando se creó y luego los ponga a lo que necesitemos. Después, en el Dispose, los cambiará otra vez a los valores iniciales:
public class ManageAllowUnsafeUpdates : IDisposable
{
    private readonly bool allowUnsafeUpdatesStatus;
    private readonly SPWeb Web;

    public ManageAllowUnsafeUpdates(SPWeb Web)
    {
        this.Web = Web;
        allowUnsafeUpdatesStatus = Web.AllowUnsafeUpdates;
        Web.AllowUnsafeUpdates = true;
    }

    public void Dispose()
    {
        Web.AllowUnsafeUpdates = allowUnsafeUpdatesStatus;
    }
}

Usarlo es así de simple:
using (new ManageAllowUnsafeUpdates(Web))
{
    ListItem[this.FieldName] = (String)value;
    ListItem.Update();
}

Y no te tienes que preocupar nunca más de si el valor estaba a true o false antes porque la clase se ocupará de todo por ti.

Este código es un poco tonto, pero creo que sirve bien para demostrar la idea.

No hay comentarios:

miércoles, 17 de abril de 2013

Capturando Excepciones Incapturables

Mi aplicación ha estado funcionando perfectamente hasta hoy. Ahora, cada vez que la lanzo revienta sin más información que el temido CLR20r3.


Description:

  Stopped working



Problem signature:

  Problem Event Name: CLR20r3

  Problem Signature 01: appName.exe

  Problem Signature 02: 1.0.0.0

  Problem Signature 03: 516eb9fb

  Problem Signature 04: mscorlib

  Problem Signature 05: 2.0.0.0

  Problem Signature 06: 4a27471d

  Problem Signature 07: 20c8

  Problem Signature 08: 100

  Problem Signature 09: N3CTRYE2KN3C34SGL4ZQYRBFTE4M13NB

  OS Version: 6.1.7600.2.0.0.274.10

  Locale ID: 2057


He leído en internet que no me pasa esto a mi solo.

Y lo más molesto es que cuando lo estoy debugando no falla...

Al final encontré un post con respuestas Handling “Unhandled Exceptions” in .NET 2.0.

Y saqué este código, que puse en el Main de la aplicación:
AppDomain.CurrentDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs e)
 {
  EventLog.WriteEntry("appName", string.Format("{0} – IsTerminating = {1}", e.ExceptionObject.ToString(), e.IsTerminating), EventLogEntryType.Error, 001);
 };
Entonces ejecuté la aplicación y reventó también, pero esta vez me dejó una hermosa excepción en el event viewer.

Si quieres saber lo que pasaba es que no era capaz de cargar una DLL que estaba esperando.

Gracias Mark.

No hay comentarios:

Los precios de las Máquinas Virtuales de Windows Azure IaaS son competitivos pero no baratos

Como probablemente sabes Microsoft acaba de lanzar la nueva plataforma de IaaS en Azure. Puedes ver todos los detalles aquí.

Todo está muy bien, pero no me gustan los precios...

Los pantallazos tienen una pinta genial (no he tenido tiempo de probarlo últimamente) y han incluido más plantillas, incluida una de prueba de SharePoint 2013 qué caducará en octubre de este año.

Pongo lo de prueba en negrita porque ¿Quién va a pagar $270 al mes para probar una máquina que se autodestruirá dentro de seis meses?

La grandeza del IaaS es que cualquiera puede crear cualquier cosa sin tener que soltar un montón de pasta en hardware, así lo veo yo. Pero, por otro lado, si el coste de la plataforma es tan cercano al del hosting tradicional, ¿dónde está la gracia?

Una búsqueda rápida te muestra cómo puedes conseguir una máquina con 4 Corea 2GB (RAM) y 500GB (HDD) por £79 al mes, ¿por qué pagar £85 por una máquina parecida albergada en la nube?

La ventaja principal de Azure es que puedes crear MVs en minutos mientras que en un distribuidor tradicional tienes que llamar por teléfono y, normalmente decirles con un mes de antelación que quieres cancelar el servicio.

Si quieres crear una granja para probar cómo conectar todo puedes hacerlo, configurarlo, jugar un poco y despues borrarlo todo por un dolar la hora, eso está bien, pero si quieres algo más estable las diferencias entre Azure y un hosting tradicional no son tan grandes.

No hace falta decir que la tecnología es asombrosa, con balanceo de carga, redes virtuales, nuevas plantillas y las máquinas nuevas de 56GB de RAM.

Y tampoco hace falta decir que tengo unas ganas enormes de ponerle las manos encima.

Pero todavía lo veo caro.

No hay comentarios: