Visualizzazione post con etichetta C#. Mostra tutti i post
Visualizzazione post con etichetta C#. Mostra tutti i post

mercoledì 27 maggio 2015

Custom ribbon in SharePoint 2013

Nel post di oggi verranno mostrati i passaggi per creare un custom ribbon nella barra multifunzione di SharePoint.

Per prima cosa è necessario creare una nuova SharePoint solution vuota in Visual Studio.

Aggiungere quindi un Empty Element, che servirà per definire lo stile e il comportamento del nostro ribbon.

Date un nome parlante all'elemento in modo da riconoscerlo tra gli altri.

A questo punto l'unica cosa che occorre fare è definire nel file Element.xml tutte le proprietà necessarie al funzionamento della nostra soluzione.

Riporto un esempio di seguito:

Andiamo ad analizzare da vicino il codice.

Nel tag CustomAction:
  • Id: indica l'identificativo univoco del ribbon
  • Location: il posto dove verrà visualizzato il ribbon (https://msdn.microsoft.com/en-us/library/office/ee537543.aspx)
  • RegistrationType: il ribbon può essere visibile in vari punti all'interno di SharePoint, come List,ContentType,ProgId e FileType
  • RegistrationId: va a specificare su quale tipo di lista deve essere pubblicata il ribbon
  • Title: il titolo del ribbon
CommandUIDefinition definisce l'interfaccia grafica del nostro ribbon:
  • Location: attributo molto importante, che va ad indicare in quale punto dovrà essere inserito il ribbon all'interno della barra multifunzione. Questo attributo è legato al tipo di lista definito in custom action e al tipo di elemento definito nel type.
    è possibile sovrascrivere un ribbon già esistente andando a settare uno di questi valori https://msdn.microsoft.com/en-us/library/office/ee537543.aspx, in alternativa è possibile aggiungere il ribbon ad un nodo figlio dell'elemento, nell'esempio viene inserito nei figli del tab action
Button è il controllo che verrà inserito nel ribbon, è possibile scegliere tra i seguenti controlli https://msdn.microsoft.com/en-us/library/office/ff458373.aspx#sectionSection1
  • Id: identificativo univoco del controllo
  • Command: riferimento del comando definito nell'elemento CommandUIHandler
  • Image16by16 e Image32by32: immagini da visualizzare nel ribbon
  • LabelText: testo da visualizzare nel controllo
  • Alt: testo alternativo
  • TemplateAlias: usato per dimensionare e posizionare il controllo nel gruppo dei ribbon
CommandUIHandler definisce gli eventi e le azioni utilizzabili nei controlli definiti in precedenza
  • Command: identificativo del comando
  • CommandAction: comando da eseguire all'attivazione dell'evento.
    NB: è necessario sapere che sono disponibili alcuni token che vengono sostituiti runtime, che indicano dove ci troviamo all'interno dell'applicazione di SharePoint 
    • {ItemId} 
    • {ItemUrl}
    • {RecurrenceId}
    • {SiteUrl} 
    • {ListId}
    • {ListUrlDir} 
    • {Source} 
    • {SelectedListId} 
    • {SelectedItemId}
A questo punto non rimane che deployare e vederne l'effetto.

Enjoy!

lunedì 3 novembre 2014

Entity Framework - The stored procedure return no columns in the model creation

Accade molto spesso di dover utilizzare stored procedure dinamiche o che utilizzano tabelle temporanee per la selezione dei dati.

Se andassimo a mappare queste stored procedure, nel model dell'Entity Framework, il wizard non riuscirebbe a recuperare le informazioni dei metadata, restituiti dalla stored.

L'EF non supporta l'importazione di stored procedure che per la costruzione dei risultati utilizzano:
  • Query dinamiche
  • Tabelle temporanee
Come si comporta l'EF quando tenta di mappare una stored procedure nel model, recuperando i metadati?
  1. Invoca la stored, passando tutti i parametri a null, 
  2. Per prevenire qualunque operazione pericolosa che possa comportare variazioni sul database, esegue il comando prima della sua esecuzione
Tramite questo comando, la stored procedure ritornerà solo i metadati delle colonne e il loro risultato, ma la logica interna non verrà eseguita.
Ma poichè la logica non viene eseguita dal wizard, negli scenari con tabelle temporanee o query dinamiche, la struttura dei metadati risulterà vuota.

A questo punto si hanno due scelte per ovviare a questo problema:

  • Definire manualmente un complex type di ritorno
  • Aggiungere in testa alla stored procedure
Quest'ultimo comando permette al codice della stored di essere eseguito normalmente, eseguendo completamente la logica all'interno definita.

Ma come fare fare a introdurre questo comando nella stored procedure evitando di toglierlo e rimetterlo in ogni compilazione?
Introducendo questo IF statment in cima alla stored:

Quando FMTONLY è settato a on (dal wizard di import dell'EF), l'esecuzione della stored procedure causa uno strano comportamento che permette di ignorare le istruzioni condizionali (come nel nostro caso IF 1=0), ignorando ogni qualsiasi logica e ritornando il possibile set di risultati che il codice della stored genera.

In questo modo è possibile introdurre il trick:
l'IF non verrà considerato nella normale esecuzione della stored, ma solamente quando FMTONLY è ON (wizard).

martedì 20 maggio 2014

Easy way to decrypt and encrypt using Advances Encryption Standard Algorithm (AES) in .NET C#

A volte si rende necessario usare algoritmi di crittografia simmetrica per rendere criptati i dati all'interno dei nostri sistemi.

Uno schema di crittografia simmetrica è caratterizzato dalla proprietà che, data la chiave di cifratura "e", sia facilmente calcolabile la chiave di decifratura "d". Un caso particolare, che è quello quasi sempre utilizzato nella pratica, è l'utilizzo di una stessa chiave condivisa sia per l'operazione di cifratura che per quella di decifratura (fonte Wikipedia)

Possiamo quindi utilizzare algoritmi di criptazione come AES in modo da rendere sicuri i nostri dati, come ad esempio può avvenire per i dati memorizzati nei cookie.

Qui vengono riportati due metodi per eseguire l'encrypt e il decrypt del nostro array di byte:

La chiamata a questi due metodi potrà essere fatta nel seguente modo:

NB: può essere utile recuperare dei valori di chiave e vettore validi, in modo da permettere la crittografia simmetrica, in maniera automatica, nel seguente modo:

mercoledì 12 marzo 2014

HOW TO - Change culture info in .NET application

Accade molto spesso che durante lo sviluppo del nostro applicativo le conversioni di numeri e date a partire da stringhe avvenga con successo.

Su un ambiente di collaudo o produzione però non è detto che queste conversioni abbiano esito positivo. 
Per questo molte volte si ricorre alla tecnica di cambiare le impostazioni di cultura in fase di esecuzione dell'applicativo.

Di seguito un breve metodo per cambiare queste impostazioni:










Enjoy!

mercoledì 15 gennaio 2014

HOW TO: WCF - Reusing types in referenced assemblies

Lavorando con i WCF e implementando uno strato di servizio nelle nostre applicazioni, molte volte si rende necessario dover utilizzare i medesimi tipi di dati sul client (DataContract).

In questo articolo vedremo come poter utilizzare la medesima struttura di datacontract tra client e server in ambito di comunicazione WCF.

A seconda del metodo che si preferisce utilizzare, se generare la classe proxy del WCF tramite lo strumento di svcutil o tramite l'aggiunta della Service Reference, gli oggetti utilizzati per effettuare le chiamata al servizio saranno creati in base alla lettura delle informazioni xml contenuti nel wsdl.




Se provassimo ad effettuare una chiamata al servizio tutto funzionerebbe correttamente, ma a tutti gli effetti staremo utilizzando un tipo complesso di dato che tramite la sua serializzazione viene correttamente letto dal server tradotto nel DataContract definito in origine.



Se il client e il server potessero condividere lo stesso DataContract come potremmo fare a utilizzare l'oggetto complesso in entrambi i livelli?


È possibile definire in questo caso le referenze e gli oggetti che il client deve utilizzare per invocare il servizio del WCF.
Sarà quindi necessario che:

1) Il client deve avere la referenza alla class library contenente i data contract



2)Se utilizziamo Visual Studio per aggiungere la service reference, nella sezione advanced, è possibile definire quali assembly condivisi utilizzare per le chiamate al servizio.



in alternativa, se preferiamo utilizzare il comando di svcutil è necessario aggiungere come attributo /reference o /r impostando il path dell'assembly da utilizzare per la generazione della classe proxy.

Il risultato sarà il seguente:



Il client e il server utilizzeranno lo stesso DataContract.
Questo apporta un notevole vantaggio in fase di sviluppo e mantenimento dell'applicazione client server: se dovesse essere necessario aggiungere una property all'interno del data contract, è possibile farlo senza rigenerare la classe proxy o aggiornare il servizio.

In questo modo il data contract può essere gestito e inviato al client senza ulteriori trasformazioni in elementi di DTO, evitando inutile riscrittura di codice.

NB: è possibile generare la classe di proxy anche utilizzando visual studio tramite la "Add service reference".
All'interno della nostra solution sarà presente il file che potremmo includere singolarmente come analogamente faremmo utilizzando il tool di svcutil.




NBB: quanto detto sopra non vale se si utilizza XmlSerializer per il data contract.

link esterni:
http://blogs.msdn.com/b/youssefm/archive/2009/10/09/reusing-types-in-referenced-assemblies-with-svcutil-s-r-switch.aspx

http://paxcel.net/blog/sharing-datacontract-across-wcf-services-without-distributing-separate-copies-to-the-client/

http://msdn.microsoft.com/en-us/library/aa347733(v=vs.110).aspx

venerdì 4 ottobre 2013

HOW TO: Use Transaction over WCF Service

Nel presente articolo, verrà trattata le modalità di utilizzo delle transazioni attraverso i WCF service.

Questa modalità operativa può risultare utile nel caso in cui si utilizzi un layer WCF service per le connessioni e le operazioni alla base dati.

Per utilizzare questo tipo di transazioni avremo bisogno di includere la classe System.Transactions.

Di seguito la reference per capirne il funzionamento:

Per prima cosa sarà necessario abilitare la transazione al nostro servizio. 
Per fare ciò, sarà necessario decorare la firma dei metodi nella nostra interfaccia WCF (ServiceContract) nel seguente modo:

[TransactionFlow(TransactionFlowOption.Allowed)]

Questo permetterà specificare che l'operazione del servizio accetta l'utilizzo delle transazioni da parte del client.
Abilitare quindi la transazione al metodo del servizio, decorandolo con il seguente OperationBehavior:

[OperationBehavior(TransactionScopeRequired = true)]

Configurare il servizio nel seguente modo:

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="TransactionalBind" transactionFlow="true">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="Transaction.service">
        <endpoint address="" contract="Transaction.Iservice" binding="wsHttpBinding" bindingConfiguration="TransactionalBind"></endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
        multipleSiteBindingsEnabled="true" />
  </system.serviceModel>


NB: 
  1.  è necessario che il servizio venga esposto con il protocollo di trasporto wsHttpBindings
  2. è necessario specificare l'attributo transactionFlow="true" per permettere l'abilitazione delle transazioni alla connessione wsHttpBindings.
Referenziare sul client il servizio appena creato, settando l'attributo transactionFlow a true:

<binding name="WSHttpBinding_Iservice" transactionFlow="true">

Siamo pronti a questo punto per effettuare le chiamate al nostro servizio.
Faremo ciò utilizzando una transazione che specificheremo tramite la direttiva using:

using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
{
    try
    {
        Service.IserviceClient obj = new Service.IserviceClient();
        obj.DO1();

        obj.DO2();

        //throw new Exception("test new exception");

        ts.Complete();
    }
    catch (Exception ex)
    {
        ts.Dispose();
    }

}

Il metodo Complete eseguirà il commit della transazione; al contrario il metodo dispose eseguirà il rollback in caso di exception.

lunedì 8 luglio 2013

HOW TO: Verificare se un utente è in uno o più gruppi di Sharepoint

Di seguito l'estratto di codice per verificare se un utente è contenuto in uno o più gruppi SharePoint.
Si presume che i nomi dei gruppi siano separati dal carattere ;



Invocabile nel seguente modo:


martedì 26 febbraio 2013

Recupero utente loggato Sharepoint 2010/2013 - Claims Based vs Classic Mode

Nelle applicazioni Sharepoint per recuperare l'utente loggato è sufficiente recuperare il login name dall'istanza del sito corrente nel seguente modo:
var strUsername = SPContext.Current.Web.CurrentUser.LoginName;
Questo funziona nel caso in cui la nostra autenticazione sia in "Classic Mode".
Nel in cui la il nostro tipo di autenticazione sia di tipo "Claims based" il risultato dell'istruzione sopra riportata sarà il seguente:
i:0#.w|Domain\ username
Occorrerà quindi differenziare le due tipologie di autenticazione utilizzando lo strumento SPClaimProviderManager fornito da Sharepoint contenuto in Microsoft.SharePoint.Administration.Claims
string strUsername = string.Empty;
 
SPClaimProviderManager mgr = SPClaimProviderManager.Local;
 
if (SPClaimProviderManager.IsEncodedClaim(SPContext.Current.Web.CurrentUser.LoginName))
    strUsername = mgr.DecodeClaim(SPContext.Current.Web.CurrentUser.LoginName).Value;
else
    strUsername = SPContext.Current.Web.CurrentUser.LoginName;
Di seguito alcuni riferimenti al tema:
http://www.wictorwilen.se/Post/How-Claims-encoding-works-in-SharePoint-2010.aspx 
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.claims.spclaimprovidermanager.aspx
http://blog.mastykarz.nl/programmatically-converting-login-name-claim/

venerdì 22 febbraio 2013

CAML Query e CamlexNET

Un pò di documentazione sul linguaggio CAML

Per creare e modificare queste query utilizzeremo il tool CamlexNET.
Di seguito alcuni esempi di utilizzo:
using CamlexNET;
using System.Linq.Expressions;

var expressions = new List<Expression<Func<SPListItembool>>>();
 
if (!string.IsNullOrEmpty(AreaTematica))
{
    expressions.Add(x => ((string)x["AreaTematica"] == AreaTematica || (object)x["AreaTematica"] == null));
}
 
 
if (!string.IsNullOrEmpty(FamigliaProdotto))
{
    expressions.Add(x => ((object)x["FamigliaProdotto"] == FamigliaProdotto || (object)x["FamigliaProdotto"] == null));
}
 
if (!string.IsNullOrEmpty(Societa))
{
    expressions.Add(x => ((object)x["SocietaGruppo"] == Societa || (object)x["SocietaGruppo"] == null));
}

var xml = Camlex.Query().WhereAll(expressions).ToString();

SPQuery query = new SPQuery();
query.Query = qry;
var items = list.GetItems(query);

Recuperare le Primary Key di una tabella utilizzando Linq to SQL

Di seguito vengono illustrati i passaggi per recuperare e utilizzare i nomi delle Primary Key da una generica Tabella Linq



Utilizzo una classe custom per mapparmi gli attributi che mi serve recuperare
public class TableModel
{
    public string tableName { getset; }
    public string tableDesc { getset; }
    public string DataContextTableName { getset; }
    public string[] DataKeyNames { getset; }
}
 
public static List<TableModel> GetTabelle()
{
    var Context = GetContext();
 
    var dbTables = Context.Mapping.GetTables();
 
 
    var t = (from ta in dbTables
                select new TableModel()
                {
                    tableName = ta.TableName,
                    tableDesc = ta.TableName.Replace("dbo."string.Empty),
                    DataContextTableName = ta.RowType.Name + "s",
                    DataKeyNames = GetPrimaryKey(ta.RowType.Type).ToArray<string>()
                }).ToList();
 
 
    return t;
}
Recupero le Primary key dalla tabella


public static List<string> GetPrimaryKey(Type T)
{
    PropertyInfo[] infos = T.GetProperties();
    List<string> PKProperty = new List<string>();
    foreach (PropertyInfo info in infos)
    {
        var column = info.GetCustomAttributes(false)
            .Where(x => x.GetType() == typeof(ColumnAttribute))
            .FirstOrDefault(x =>
            ((ColumnAttribute)x).IsPrimaryKey &&
            ((ColumnAttribute)x).DbType.Contains("NOT NULL"));
 
 
        if (column != null)
        {
            PKProperty.Add(((System.Reflection.MemberInfo)(info)).Name);
        }
    }
 
    if (PKProperty == null)
    {
        throw new NotSupportedException(
            T.ToString() + " has no Primary Key");
    }
    return PKProperty;
 
}
Utilizzo, ad esempio, delle primary key per l'attributo DataKeyNames di una griglia RadGrid alimentata con un LinqDataSource
this.rgTables.MasterTableView.DataKeyNames = ((List<TableModel>)(ViewState[ListTable]))
                    .Where(t => t.DataContextTableName == cb_tabelle.SelectedValue)
                    .FirstOrDefault().DataKeyNames;