in

DotNetSide

Dot Net South Italy Developers User Group

Tips

  • Copiare file nello storage di Windows Phone 7

    Autore : Vito Arconzo

    In molte occasioni, durante lo sviluppo di applicazioni per Windows Phone 7, abbiamo la necessita di copiare file che possono arrivare da sorgenti diverse sia web che locali nello storage del dispositivo. Le API di Windows Phone 7 ci mettono a disposizione (come per Silverlight) un spazio dedicato ed esclusivo all’app che lo utilizza senza, ovviamente, la possibilità di accedervi ad altre applicazioni.

    Non avendo un vero e proprio File System e non potendo quindi usare le solite funzionalità di copia del namespace System.IO.File etc… possiamo usare il codice seguente che fa uso di un stream che legge dalla sorgente e scrivo il risultato nello storage.

     

    IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
    
    using (IsolatedStorageFileStream fs = new IsolatedStorageFileStream("data.xml", FileMode.Create, FileAccess.Write, store))
    {
    	if (!store.FileExists("data.xml"))
    	{
    		StreamResourceInfo sri = Application.GetResourceStream(new Uri("data.xml", UriKind.Relative));
    		byte[] bytesInStream = new byte[sri.Stream.Length];
    		sri.Stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
    
    		fs.Write(bytesInStream, 0, bytesInStream.Length);
    		fs.Flush();
    	}
    }
  • Upload e resize di Immagini in Asp.Net

    di Giulio Preite

     

    Più di una volta mi sono trovato di fronte al problema di fare l’upload di immagini verso un sito internet e di ridimensionarle rendendole adatte alla pagina che le andrà a contenere.

    Ci sono differenti approcci al problema, da quello più semplice, che ridimensiona le immagini quando vengono richiamate  dall’utente, per così dire “on the fly”, a soluzioni più complesse, che recuperano dimensioni e risoluzione, al fine di attuare il resize più adatto.

    La mia si affianca ad esse, utilizzando lo streaming. Ecco quindi la classe:

    public class ResizeManager
    {
        private void ResizeAndSave(Stream imgStr, string FileName)
        {

            //creo il bitmap dallo stream
            System.Drawing.Image bmpStream = System.Drawing.Image.FromStream(imgStr);

            //creo un nuovo bitmap ridimensionandolo 
            double q = bmpStream.Width / 3;
            int W;

            W = (int)q;
            double g = bmpStream.Height / 3;

            int H;

            H = (int)g;
            Bitmap img = new Bitmap(bmpStream, new Size(W, H));

            //salvo l'immagine ridimensionata
            img.Save(FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
        }

        public string Upload(FileUpload File1)
        {

            //controllo che sia un jpg
            if (File1 != null || File1.PostedFile.ContentType == "image/jpeg")
            {
                string myFoto = File1.FileName;          

                //salvo così com'è
                File1.SaveAs(@"C:........\Public\" + myFoto);

                //Creo lo Stream e lo passo alla funzione insieme alle dimensioni al percorso e al nome del file.
                MemoryStream DataM = new MemoryStream(File1.FileBytes);
                ResizeAndSave(DataM, @"C:…..\Public\Thumbs\" + myFoto);
                return myFoto;
            }

            // se la verifica non va a buon fine viene restituito il logo.
            else { return "logo.jpg"; };     
        }
    }

    La classe recupera il file (caricato tramite l’user control FileUpload) crea la bitmap dallo stream (il file non è ancora caricato sul server) e lo ridimensiona.

    Ho usato il coefficente 3, ma può anche essere diverso. Preferisco utilizzare dei coefficienti, poiché non sempre la dimensione verticale è direttamente proporzionale a quella orizzontale, e, inoltre, possiamo trovarci di fronte ad una immagine che ha una altezza maggiore della larghezza. Una soluzione alternativa consiste nel recuperare le dimensioni e regolarsi di conseguenza, nel momento del resize.

    Una volta completato il resize, l’immagine, cosi modificata (in streaming) viene salvata (uplodata) nella cartella Thumbs.

    Infine, l’immagine originale (anche in questo caso la si può ridimensionare) viene salvata nella cartella Public.

    Un altra cosa molto importante è questa: va passato il percorso fisico della cartella all’interno del server, partendo ad esempio da C: o D:.

    Un’ultima cosa, i namespace:

    using System;
    using System.Collections.Generic;
    using System.Web;
    using System.IO;
    using System.Net;
    using System.Drawing;
    using System.Web.UI.WebControls;

    Al prossimo tips.

  • ListView riordinabile con WPF

    Autore: Vito Arconzo

    Una delle esigenze più frequenti durante lo sviluppo di applicazioni con Windows Presentation Foundation è la rappresentazione di dati nel classico formato Grid. In Windows Presentation Foundation, almeno fino alla versione 3.5 del framework, non è incluso un controllo nativo GridView e, per questi casi, solitamente, se non si vuole ricorrere a controlli di terze parti, viene utilizzato il controllo ListView.

    Il controllo ListView di WPF, infatti, mette a disposizione un tipo di visualizzazione di tipo, appunto, GridView che permette la gestione di più colonne. Nell’esempio seguente viene definito un controllo ListView con modalità di visualizzazione GridView composta da 4 colonne in binding con alcune proprietà dell’entità Person.

    <ListView x:Name="listPersons" ItemsSource="{StaticResource persons}"
              BorderThickness="0" Margin="5"
              GridViewColumnHeader.Click="GridViewColumnHeader_Click" >
        <ListView.View>
            <GridView AllowsColumnReorder="True">
                <GridViewColumn Header="ID" 
                                DisplayMemberBinding="{Binding Path=ID}" 
                                Width="50" />
                <GridViewColumn Header="FirstName" 
                                DisplayMemberBinding="{Binding Path=FirstName}" 
                                Width="100"/>
                <GridViewColumn Header="LastName" 
                                DisplayMemberBinding="{Binding Path=LastName}" 
                                Width="100"/>
                <GridViewColumn Header="City" 
                                DisplayMemberBinding="{Binding Path=City}" 
                                Width="80"  />
            </GridView>
        </ListView.View>
    </ListView>

    Nel listato, come noterete, viene definito l’handler dell’evento Click di GridViewColumnHeader dove verrà gestito, appunto, il riordinamento della colonna cliccata.

    image

    Per ottenere l’ordinamento della collection utilizzeremo un metodo chiamato Sort che, attraverso l’uso di una CollectionViewSource effettua l’ordinamento per il campo passato come parametro al metodo (sortBy).

    private void Sort(string sortBy, ListSortDirection direction)
    {
        ICollectionView dataView = CollectionViewSource.GetDefaultView(listPersons.ItemsSource);
    
        dataView.SortDescriptions.Clear();
        SortDescription sd = new SortDescription(sortBy, direction);
        dataView.SortDescriptions.Add(sd);
        dataView.Refresh();
    }

    Passiamo ora alla gestione dell’evento di click sull’header di una colonna della ListView.

    GridViewColumnHeader _lastSelectedHeader = null;
    ListSortDirection _lastDirection = ListSortDirection.Ascending;
    
    void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
    {
        GridViewColumnHeader selectedHeader = e.OriginalSource as GridViewColumnHeader;
        ListSortDirection direction;
    
        if (selectedHeader != null)
        {
            if (selectedHeader.Role != GridViewColumnHeaderRole.Padding)
            {
                if (selectedHeader != _lastSelectedHeader)
                {
                    direction = ListSortDirection.Ascending;
                }
                else
                {
                    if (_lastDirection == ListSortDirection.Ascending)
                    {
                        direction = ListSortDirection.Descending;
                    }
                    else
                    {
                        direction = ListSortDirection.Ascending;
                    }
                }
    
                string header = string.Empty;
                if (selectedHeader.Column.CellTemplateSelector != null)
                {
                    header = selectedHeader.Column.Header.ToString();
                }
                else if (selectedHeader.Column.DisplayMemberBinding != null)
                {
                    header = ((Binding)selectedHeader.Column.DisplayMemberBinding).Path.Path;
                }
                else
                {
                    return;
                }
    
                Sort(header, direction);
    
                if (direction == ListSortDirection.Ascending)
                {
                    selectedHeader.Column.HeaderTemplate =
                      FindResource("HeaderTemplateArrowUp") as DataTemplate;
                }
                else
                {
                    selectedHeader.Column.HeaderTemplate =
                      FindResource("HeaderTemplateArrowDown") as DataTemplate;
                }
    
                // Remove arrow from previously sorted header
                if (_lastSelectedHeader != null && _lastSelectedHeader != selectedHeader)
                {
                    _lastSelectedHeader.Column.HeaderTemplate = null;
                }
    
                _lastSelectedHeader = selectedHeader;
                _lastDirection = direction;
            }
        }
    }

     

    Come potete vedere, la logica presente nell’evento è abbastanza semplice. Qui, infatti, viene, innanzitutto, intercettato l’intestazione cliccata, e, in base alla direzione di ordinamento (Ascending o Descending) viene applicato un template diverso per visualizzare una freccetta nell’intestazione per identificarnet, appunto, l’orientamento.

    Ovviemente, in questo evento, viene richiamata il metodo Sort dichiarato in precedenza. Il codice XAML per la definizione dei template da utilizzare per la visualizzazione delle freccetta di indicazione nelle intestazioni è il seguente.

    <DataTemplate x:Key="HeaderTemplateArrowUp">
        <DockPanel>
            <TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
            <Path x:Name="arrow"
        StrokeThickness = "1" Fill="Black"
        Data="M 5,10 L 15,10 L 10,5 L 5,10"/>
        </DockPanel>
    </DataTemplate>
    
    <DataTemplate x:Key="HeaderTemplateArrowDown">
        <DockPanel>
            <TextBlock HorizontalAlignment="Center" Text="{Binding }"/>
            <Path x:Name="arrow"
        StrokeThickness="1" Fill="Black" 
        Data= "M 5,5 L 10,10 L 15,5 L 5,5"/>
        </DockPanel>
    </DataTemplate>

    Concludendo, quindi, ad un click su qualsiasi intestazione di colonna, viene effettuato l’ordinamento per la colonna in oggetto e sostituito il template dell’intestazione stessa affinchè venga in essa visualizzata una freccetta per identificarne la direzione dell’ordinamento effettuato.

    image

    Posted Jun 30 2009, 02:00 PM by DotNetSide Staff
    Filed under:
  • HttpHandler per un'immagine casuale

    Autore: Luca Barbi

    Gli HTTP Handler sono dei meccanismi di ASP.NET che si occupano di elaborare le risposte a specifiche richieste HTTP e fornirle, secondo la forma più consona, al richiedente.

    Questo Generic Handler restituisce un'immagine a caso tra quelle presenti in una directory di un sito web.

    Si tratta di un file con estensione .ashx che non ha bisogno di essere compilato, né di essere registrato nel file web.config. Basterà solamente far riferimento ad esso come URL di un'immagine, indipendentemente da dove questo sia utilizzato.

    Ad esempio, supponendo di chiamare il nostro file ImmagineCasuale.ashx e di metterlo nella root del sito web www.miosito.it, potremmo utilizzarlo per visualizzare un'immagine casuale In diversi modi.

    • Attraverso un tag HTML in una pagina web
    	<img src="/ImmagineCasuale.ashx" alt="immagine casuale"/> 
    • In un foglio di stile
    	div.intestazione { 
    background-image: url (/ImmagineOraria.ashx);
    }
    • In un controllo server web ASP.NET
    	<asp:Image ID="ImmagineCasuale" runat="server" ImageUrl="~/ImmagineCasuale.ashx" 
    AlternateText="Immagine Casuale" />

    E' possibile, inoltre, chiedere l'immagine casuale da un altro sito, sarà sufficiente indicare l'URL completo: http://www.miosito.it/ImmagineCasuale.ashx

    Ecco il codice:

    <%@ WebHandler Language="VB" Class="ImmagineCasuale" %>

    Imports System
    Imports System.Web

    Public Class ImmagineCasuale : Implements IHttpHandler

    ' qui indico la directory in cui ci sono le immagini
    Const DIRIMMAGINI = "immagini/fotocasuali"

    ' implementazione del metodo
    Public Sub ProcessRequest(ByVal context As HttpContext) _
    Implements IHttpHandler.ProcessRequest
    ' metto i nomi dei file .jpg in un array
    ' (potrei farlo anche per altre estensioni)
    Dim nomiFileImmagine() As String = _
    System.IO.Directory.GetFiles(context.Server.MapPath(DIRIMMAGINI), "*.jpg")
    ' se ci sono immagini ne estraggo una a caso e la invio come HttpResponse
    If nomiFileImmagine.Length > 0 Then
    Dim n As Integer
    Dim vMax As Integer
    vMax = nomiFileImmagine.GetUpperBound(0)
    Randomize()
    n = CInt(Int((vMax + 1) * Rnd()))

    Dim response As Web.HttpResponse = context.Response
    response.ContentType = "image/jpeg"
    response.Cache.SetCacheability(HttpCacheability.Public)
    response.BufferOutput = False
    response.WriteFile(nomiFileImmagine(n))
    response.End()
    End If
    End Sub
    ' poiché si tratta di sola lettura imposto IsReusable a True
    Public ReadOnly Property IsReusable() As Boolean _
    Implements IHttpHandler.IsReusable
    Get
    Return True
    End Get
    End Property
    End Class

    Un esempio di possibile utilizzo potrebbe essere un banner pubblicitario di una pagina web, in cui ad ogni richiesta lo sponsor varia casualmente.

    Possibili varianti: cambiare la directory o scegliere l'immagine a seconda dei parametri passati attraverso una QueryString, oppure scegliere l'immagine a seconda dell'ora.

    In quest'ultimo caso il codice potrebbe essere:

    <%@ WebHandler Language="VB" Class="ImmagineOraria" %> 
    Imports System
    Imports System.Web

    Public Class ImmagineOraria : Implements IHttpHandler

    Const DIRIMMAGINI = "immagini/orarie"

    Public Sub ProcessRequest(ByVal context As HttpContext) _
    Implements IHttpHandler.ProcessRequest

    Dim nomiFileImmagine() As String = _
    {"mattino", "giorno", "pomeriggio", "sera", "notte"}
    Dim n, ora As Integer
    ora = DateTime.Now.Hour
    Select Case ora
    Case 22 To 24, 0 To 6
    n = 4
    Case 7 To 9
    n = 0
    Case 17 To 19
    n = 2
    Case 20 To 21
    n = 3
    Case Else
    n = 1
    End Select

    Dim response As Web.HttpResponse = context.Response
    response.ContentType = "image/jpeg"
    response.Cache.SetCacheability(HttpCacheability.Public)
    response.BufferOutput = False
    response.WriteFile(context.Server.MapPath(DIRIMMAGINI & _
    nomiFileImmagine(n) & ".jpg"))
    response.End()
    End Sub

    Public ReadOnly Property IsReusable() As Boolean _
    Implements IHttpHandler.IsReusable
    Get
    Return True
    End Get
    End Property
    End Class

    In allegato una solution per VS 2005 con entrambi questi handler e due pagine html per provarli.

  • DataObjectAttribute e ObjectDataSource

    Autore: Mario Ferrante

    L’attributo DataObject rende più facile la ricerca delle classi che si vogliono legare ad un controllo DataBound durante la configurazione dell’ObjectDataSource.
    Quando si utilizza l’ObjectDataSource, la prima cosa che devo fare è scegliere l’oggetto Business da utilizzare per recuperare o gestire i dati e per legarli ad un controllo DataBound:

    Purtroppo se chiedo al wizard dell’ObjectDataSource di mostrarmi solo i “Data Components” (come in figura), la maggior parte delle volte il risultato che ottengo è un menù a discesa vuoto.
    Dunque non rimane che levare la spunta a “Show only data components” e cercare l’oggetto Business che mi interessa tra tutti quelli a cui è referenziata la mia applicazione, come si vede nella figura successiva.

     

    Poco male nel caso di piccole applicazioni, ma nel caso di applicazioni molto grandi o che comunque referenziano molti assemblies il problema diventa un po’ più serio.
    Ed è qui che viene in aiuto l’attributo DataObjectAttribute o semplicemente DataObject. Questo attributo può essere usato a livello di classe, ma anche a livello dei singoli metodi.

    L’Attributo DataObject a livello di classe
    Supponiamo che nella mia applicazione ho una classe che mi gestisce il CRUD (Create Retrieve Update e Delete) di News a cui aggiungo, a livello di classe, l’attributo DataObject:

     

     

    Imports System.ComponentModel Namespace Mario.DotNetSide <DataObject()> _ Public Class NewsManager 'Implementazione della Classe End Class End Namespace

     

    Il risultato sarà:

    Il costruttore dell’attributo DataObject accetta anche un parametro di tipo System.Boolean, se False dichiaro esplicitamente all’Object Data Source di non considerare quella classe come Data Component.
    L’Attributo DataObject a livello di metodo

    Abbiamo usato questo attributo a livello di Classe, ma lo posso utilizzare anche a livello di metodi per definire quali di essi devono essere utilizzati per selezionare i dati, quali per inserire un record, cancellarlo o modificarlo:

     

    <DataObject()> _ Public Class NewsManager <DataObjectMethod(DataObjectMethodType.Select, True)> _ Public Function GetNews() As NewsCollection End Function <DataObjectMethod(DataObjectMethodType.Insert, True)> _ Public Function AddNews(ByVal item As News) As Integer End Function End Class

    I valori dell’enumerazione DataObjectMethodType sono autoesplicativi:

    • Delete
    • Fill
    • Insert
    • Select
    • Update

    Il secondo parametro booleano passato all’attributo (True in questo caso) indica all Object Data Source se considerare (True) o meno (False) quel metodo per una determinata funzione (ad esempio di Select).
    In .Net gli attributi hanno una fondamentale importanza, essi contribuiscono a fornire tutte quelle informazioni che costituiscono i MetaData di un’assembly. Inoltre possono influenzare il comportamento di un oggetto sia a run-time sia (come in questo caso) a design-time.

  • Membership APIs - L'enumerazione MembershipCreateStatus

    Autore: Mario Ferrante

    Quando si crea un nuovo utente utilizzando le Membership APIs (Membership e MembershipUser), può capitare che si vogliano catturare le eventuali eccezioni che questo processo può generare per fornire all’utente un messaggio più user friendly e dare più dettagli circa l’errore (ad esempio:”username già utilizzato da un altro utente”, “password invalida perché deve contenere almeno due caratteri non alfanumerici”, etc.).
    Per fare questo possiamo utilizzare l’enumerazione MembershipCreateStatus.

    Per poterla utilizzare devo prima creare una variabile di tipo MembershipCreateStatus, quindi passare per riferimento tale variabile al metodo CreateUser della classe Membership.

    In questo modo la variabile può assumere diversi valori, da Success (utente creato con successo) a DuplicateUserName, InvalidPassword e così via.

    Ecco un esempio di codice:

     

    Dim status As MembershipCreateStatus 'la nostra variabile MembershipCreateStatus
    Dim myuser As MembershipUser = _
    Membership.CreateUser(username, _
    password, email, question, answer, isActive, status)
    'la variabile status viene passata Per Riferimento
    If status = MembershipCreateStatus.Success Then
    'la registrazione del nuovo utente è avvenuta con successo
    Else
    Select Case status
    Case MembershipCreateStatus.InvalidPassword
    Response.Write(
    "La Password utilizzata non è nel formato corretto, assicurarsi che sia di almeno 6 caratteri e contenga un carattere non alfanumerico")
    Case MembershipCreateStatus.DuplicateUserName
    Response.Write(
    "L'Username usata esiste già, cambiarla e continuare con la registrazione")
    Case MembershipCreateStatus.DuplicateEmail
    Response.Write(
    "L'Email usata esiste già, cambiarla e continuare con la registrazione")
    Case 'qui possiamo sfruttare altri valori dell’enumerazione
    End Select
    End If

    Per maggiori dettagli si può dare uno sguardo al seguente link:
    http://msdn2.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx

    Posted Nov 29 2006, 09:56 AM by VitoA with 2 comment(s)
    Filed under:
  • XAML inline code

    Autore: Vito Arconzo

    Uno degli aspetti interessanti del nuovo linguaggio di markup XAML è la possibilità di avere del codice inline.

    Ecco come:

    <Window x:Class="WindowsApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="Window1_Loaded"> <x:Code> <![CDATA[ void Window1_Loaded(object sender, RoutedEventArgs e) { this.Title="Titolo...."; TextBox txt = new TextBox(); txt.Text="hello dotnetsiders!!!"; this.Content=txt; } ]]> </x:Code> </Window>
    Posted Nov 27 2006, 05:23 PM by VitoA with no comments
    Filed under:
  • Convertire HTML in Testo

    Autore: Stefano De Mattia

    Quella che segue è una funzione che converte una stringa HTML in una di testo semplice.

    Sono necessari i seguenti Imports:

    Imports System.Text
    Imports System.Text.RegularExpressions

    Il codice della funzione:

    ''' <summary>
    '
    '' Funzione che converte una stringa HTML in una di testo semplice
    '
    '' </summary>
    '
    '' <param name="html">Stringa da convertire</param>
    '
    '' <returns>Stinga semplice</returns>
    '
    '' <remarks></remarks>
    Function Html2Text(ByVal html As String) As String
    ' pattern per la rimozione dei tag HTML
    Dim pattern As String = "\<[^\>]*\>"
    Dim re As New Regex(pattern, RegexOptions.IgnoreCase)

    'qui posso modificare la formattazione sui
    'tag che mi interessano, prima di eliminarli ad esempio
    'html = html.Replace("<p>", vbCrLf)
    'html = html.Replace("<\p>", vbCrLf & vbCrLf)
    'html = html.Replace("&nbsp;", " ")
    html = html.Replace("<br />", vbCrLf)

    'applico l'espressione regolare,
    'sostituendo i caratteri speciali con la stringa vuota
    html = re.Replace(html, String.Empty)

    Return html

    End Function
    Posted Oct 31 2006, 11:53 AM by VitoA with 2 comment(s)
    Filed under: ,
  • Hyperlink in WPF

    Autore: Vito Arconzo

    Un quesito ricorrente nei forum su Windows Presentation Foundation è come creare un hyperlink per aprire il browser su una pagina web indicata.

    La risposta è differente a seconda se si tratti di un'applicazione standalone o browser.

    Browser

    Nelle applicazioni di tipo browser la cosa è molto semplice:

    <TextBlock> <Hyperlink NavigateUri="http://www.dotnetside.org" TargetName="_top"> Navigate the top-level window to DotNetSide </Hyperlink> </TextBlock>

    Standalone

    Sfortunatamente, nelle applicazioni standalone, la cosa non è così immediata e il modo più semplice è quello di utilizzare l'evento RequestNavigate del controllo HyperLink e, quindi, gestire l'apertura del browser nel code-behind:

    <TextBlock> <Hyperlink RequestNavigate="HandleRequestNavigate" Name="hl"
    NavigateUri="http://www.dotnetside.org"> Open DotNetSide in the default browser </Hyperlink> </TextBlock>
    void HandleRequestNavigate(object sender, RoutedEventArgs e) { string navigateUri = hl.NavigateUri.ToString(); Process.Start(), e.g. check to see Process.Start(new ProcessStartInfo(navigateUri)); e.Handled = true; }
    Posted Oct 17 2006, 09:00 PM by VitoA with 14 comment(s)
    Filed under: ,
  • Impedire avvio istanza MS SQL Server

    Autore: Francesco Quaratino

    Ecco alcune funzionalità poco note di MS-Sql Server, per la realizzazione di un'applicazione in grado di impedire a un'istanza di MS-Sql Server di avviarsi.

    Premetto che sarà bene provare il codice che presento di seguito, SOLTANTO in ambienti molto poco critici e MAI (!!!) in ambienti di produzione. Non deve essere bello, infatti, vedere che Sql Server non rispondere ai nostri ripetuti "inviti" ad avviarsi.

    Apriamo una connessione al nostro server sql, con credenziali di amministratore (per intenderci l'utente SA va benissimo), entrando nel contesto del database master.

     

    --Transact SQL
    USE master
    GO

    Iniziamo col creare una stored procedure di sistema, cioè che risiederà nel database master. Questa procedura avrà l'ingrato compito di arrestare il servizio SQL Server (mssqlserver è il servizio di default, mssql$istanzanominata in caso di istanza con nome) richiamando la stored procedure estesa xp_cmdShell.

    Per crearla come stored procedure di sistema, basta denominarla con il prefisso sp_.

     

    --Transact SQL
    CREATE PROC sp_StopService
    AS
    EXEC xp_cmdshell 'net stop mssqlserver', NO_OUTPUT
    GO

    A questo punto, la rendiamo una "autostart procedure". In tal modo, la nostra procedura sarà eseguita automaticamente subito dopo la partenza del servizio Sql, producendo lo spiacevole effetto di arrestare lo stesso servizio.

     

    --Transact SQL
    sp_procoption sp_StopService, 'startup', 'true'

    A questo punto, possiamo arrestare il servizio manualmente o, se preferite un po' più di suspense, riavviare il computer. Se non ci sono stati intoppi, il servizio Sql non si avvierà mai più perchè arrestato dalla nostra procedura auto-partente subito dopo l'avvio.

    Per disattivare la proprietà auto-partente della sp_StopService, è necessario avviare Sql Server in modalità applicazione mediante SQLSERVR.EXE usando il il trace flag 4022. Quindi, apriamo un prompt dei comandi e dopo esserci spostati nella directory che ospita SQLSERVR.EXE, digitiamo il comando dal prompt dei comandi

    (se istanza nominata, in questo esempio Sql2005 è il nome dell'istanza)

    sqlservr -sSql2005 -T4022

    (se istanza di default)

    sqlservr -T4022

    Quindi, per disattivare il comportamento auto-partente della nostra procedura, apriamo una connessione a Sql mediante credenziali amministrative entrando nel contesto del database master, e lanciamo:

     

    --Transact SQL
    sp_procoption sp_StopService, 'startup', 'false'

    Solo adesso, saremo in grado di avviare il servizio Sql (ma prima bisogna terminare l'esecuzione di sqlservr chiudendo la finestra DOS o premendo CTRL+BREAK). Lo scherzo è bello quando dura poco :)

    Posted Oct 12 2006, 08:00 AM by VitoA with 1 comment(s)
    Filed under:
  • Controlli dinamici in ASP.NET 2

    Autore: Vito Arconzo

    Sia con Windows Forms 2 che con ASP.NET 2 è possibile creare controlli dinamicamente.

    In Windows Forms il seguente codice da utilizzare è :

     

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim btn As New Button
    btn.Text
    = "Click"
    Me.Controls.Add(btn)
    End Sub

    Il risultato:

    Se proviamo ad utilizzare lo stesso codice in una pagina ASP.NET, invece, il risultato sarà:

    Un bell'errore di compilazione!!!!!!!!!!

    Per risolvere il problema, attualmente, è necessario includere il controllo all'interno di un contenitore come Panel o Tabella.

    Il codice corretto sarà, quindi:

     

    Dim btn As New Button
    btn.Text
    = "Click"
    ‘ aggiunge il controllo al panel
    Me.Panel1.Controls.Add(btn)
    End Sub

    In questo modo il controllo sarà aggiunto correttamente alla pagina :-)

    Posted Sep 18 2006, 01:02 AM by VitoA with no comments
    Filed under:
  • Caricare dinamicamente uno User Control

    Autore: Mario Ferrante

    Normalmente quando in una pagina aspx sono presenti User Controls, essi devono essere “registrati” nella direttiva @Register della pagina che lo contiene:

    <%@ Register Src="[path dello User Control]" TagName="myUC" TagPrefix="uc1" %>

    Quindi possono essere richiamati in qualsiasi parte del corpo della pagina attraverso una sintassi di questo tipo:

    <uc1:myUC ID="myUC1" runat="server" />

    L’IDE di Visual Studio esegue tutto questo lavoro automaticamente, basta trascinare lo User Control appena costruito dalla finestra Solution Explorer all’interno della pagina per vedere comparire la direttiva Register e tutto il resto.

    Tuttavia possono capitare situazioni in cui abbiamo la necessità di caricare degli User Control dinamicamente in base ad alcuni eventi, tipo il cambio di valore della Querystring.
    Ad esempio, supponiamo di avere tre User Control per gestire l’aggiunta, la visualizzazione e la modifica di clienti in un’applicazione di Commercio Elettronico.
    Mettiamo caso che nella pagina customers.aspx, in base al valore della chiave action della querystring, dobbiamo caricare l’User Control appropriato.
    La pagina
    customers.aspx conterrà sempilecemente un controllo Panel:

    1    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="customers.aspx.cs" Inherits="customers" %>
    2
    3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    4
    5 <html xmlns="http://www.w3.org/1999/xhtml" >
    6 <head runat="server">
    7 <title>Untitled Page</title>
    8 </head>
    9 <body>
    10 <form id="form1" runat="server">
    11 <div>
    12 <asp:Panel ID="Panel1" runat="server" Width="80%">
    13 </asp:Panel>
    14 </div>
    15 </form>
    16 </body>
    17 </html>

    Nel Code Behind associato alla pagina, customers.aspx.cs avremo:

    1    protected void Page_Load(object sender, EventArgs e)
    2 {
    3 System.Web.UI.Control myUserControl;
    4 string action = Request.QueryString["action"];
    5 switch (action) {
    6 case "add":
    7 myUserControl = LoadControl("../Controls/addCustomer.ascx");
    8 break;
    9 case "update":
    10 myUserControl = LoadControl("../Controls/updateCustomer.ascx");
    11 break;
    12 case "view":
    13 myUserControl = LoadControl("../Controls/viewCustomers.ascx");
    14 break;
    15 default:
    16 myUserControl = LoadControl("../Controls/homeCustomers.ascx");
    17 break;
    18 }
    19 this.Panel1.Controls.Add(myUserControl);
    20 }

    Nell’esempio, il caricamento dinamico dello UC viene inserito nell’evento Load della pagina in base al valore assunto da una querystring, ma è possibile eseguire questa azione all’interno di altri eventi quali il Click di una Button e così via.

    Da notare che nella pagina aspx non vi è traccia alcuna della direttiva @Register.

     
    Posted Jul 14 2006, 09:42 AM by VitoA with no comments
    Filed under:
  • Logiche di business mediante trigger

    Autore: Francesco Quaratino

    I trigger sono, talvolta, l'estremo rimedio a problemi altrimenti insormontabili. Anche se Microsoft tende a scoraggiarne l'uso, in alcuni casi è bene prenderli in seria  considerazione, come, per esempio, l'implementazione di logiche aziendali complesse che l'integrità referenziale non è in grado di supportare.

    Questo tips presenta un caso concreto in cui l'uso dei trigger favorisce le performance di un'applicazione. Mi riferisco a un'applicazione gestionale abbastanza comune, legata alla gestione acquisti di un prodotto: il calcolo dell'ultimo costo d'acquisto del prodotto.

    Conoscere il costo ultimo di un prodotto è di fondamentale importanza per riordinarlo dal fornitore più conveniente, così come per fissarne un prezzo di vendita.

    Spesso i progettisti software decidono di far calcolare il costo ultimo nel momento stesso in cui viene richiesto dall'utente, motivando tale scelta col fatto che si tratta di un “campo calcolabile”, il quale non necessità di essere ospitato permanentemente nel database (e di conseguenza trattato in fase di inserimento/modifica/cancellazione).

    Se, però, questa decisione non è supportata da un'analisi preventiva del carico di lavoro a cui sarà soggetta l'applicazione, la procedura che si occupa di calcolare il costo ultimo, rischia di diventare il collo di bottiglia di funzionalità vitali della nostra applicazione (come, per esempio, la fase di riordino dei prodotti la cui giacenza va sotto la soglia della scorta minima  prestabilita, che in alcune realtà commerciali è un'operazione svolta giornalmente e molto onerosa da un punto di vista delle risorse di sistema impegnate).

    Supponiamo quindi di trovarci di fronte al seguente database, che raccoglie gli ordini a fornitore di prodotti di natura non specificata:





    Per l'esattezza, ecco i significati delle tabelle:

    ●    [OrderHeader]: i dati generali degli ordini a fornitore
    ●    [OrderDetail]: i dati dettagliati dei prodotti ordinati
    ●    [Fornitore]: i dati dei fornitori che ci riforniscono i nostri depositi
    ●    [Prodotto]: i dati dei prodotti ordinabili ai ns fornitori

    Con questi dati a disposizione, ricavare - mediante Transact-SQL - il prezzo ultimo del prodotto per un particolare fornitore, significa scrivere questo codice:

    1    DECLARE 
    2 @codice_prodotto INT,
    3 @codice_fornitore INT
    4
    5 SET
    @codice_fornitore = 1
    6 SET @codice_prodotto = 3
    7
    8
    9 SELECT TOP 1
    10 prezzo_acquisto
    11 FROM
    12 OrderHeader H
    13 INNER JOIN
    14 OrderDetail D
    15 ON
    16 D.idHeader = H.id
    17 WHERE
    18 codice_prodotto = @codice_prodotto
    19 AND
    20 codice_fornitore = @codice_fornitore
    21 ORDER BY
    22 data_ordine
    23 DESC


    Questa query risolve il problema restituendo il dato desiderato, ma in presenza di migliaia di ordini tale risultato potrebbe giungere in tempi troppo lunghi per la pazienza di utente. Proviamo a risolvere l'eventuale problema di performance “materializzando” il campo calcolabile del prezzo ultimo, attraverso la tabella [CostoUltimoProdottoFornitore]:





    Quindi gestiamo la nuova tabella attraverso il seguente trigger creato sulla tabella [OrderDetail] che scatta in fase di inserimento e modifica:

    1    CREATE TRIGGER tr_insert_update_costo_ultimo
    2 ON dbo.OrderDetail
    3 AFTER
    4 INSERT, UPDATE
    5 AS
    6
    7 IF
    @@ROWCOUNT = 0
    8 RETURN
    9
    10 /* verifico l'esistenza nella tabella [CostoUltimoProdottoFornitore] della riga
    11 relativa al prodotto inserito o aggiornato nell'ordine */

    12 IF EXISTS
    13 (
    14 SELECT *
    15 FROM CostoUltimoProdottoFornitore C
    16 INNER JOIN Inserted i
    17 ON C.codice_prodotto = i.codice_prodotto
    18 INNER JOIN OrderHeader H
    19 ON H.id = i.idHeader
    20 AND H.codice_fornitore = C.codice_fornitore
    21 )
    22 /* ne aggiorno il costo ultimo */
    23 UPDATE C
    24 SET costo_ultimo = i.prezzo_acquisto
    25 FROM CostoUltimoProdottoFornitore C
    26 INNER JOIN Inserted i
    27 ON C.codice_prodotto = I.codice_prodotto
    28 INNER JOIN OrderHeader H
    29 ON H.id = i.idHeader
    30 AND H.codice_fornitore = C.codice_fornitore
    31 ELSE
    32 /* inserisco la riga corrispondete */
    33 INSERT INTO CostoUltimoProdottoFornitore
    34 ( codice_prodotto, codice_fornitore, costo_ultimo)
    35 SELECT i.codice_prodotto, H.codice_fornitore, i.prezzo_acquisto
    36 FROM Inserted i
    37 INNER JOIN OrderHeader H
    38 ON H.id = i.idHeader
    39
    40 RETURN
    41 GO


    In realtà, la gestione della tabella  [CostoUltimoProdottoFornitore] non si esaurisce con questo trigger. In genere, infatti, occorrerebbe trattare l'eventuale cancellazione del prodotto dall'ordine, così come la modifica del fornitore dell'ordine e tutte gli altri eventi che le applicazioni costruite sul database sono in grado di attivare. Potrebbe essere opportuno anche strutturare diversamente la tabella in modo da conservare un numero ragionevole di costi ultimi e non uno soltanto come nel nostro esempio, la cui complessità è stata volutamente mantenuta ridotta.

    N.B.: scarica lo script allegato per generare il database e il trigger di esempio.

     
     
      


     
    Posted Jul 12 2006, 08:57 AM by VitoA with no comments
    Filed under:
  • Recuperare i dati da una cella del DataGridView

     

    Autore: Michele Locuratolo

    Spesso si ha la necessità di recuperare i dati da una cella di una DataGrid. La regola vuole che tali elementi vengano recuperati dal DataSource e non dalla DataGridView in quanto, come spesso accade, nella gliglia potrebbero non essere mostrati tutti i dati.
    Per farlo, usiamo il seguente codice:


    1    private object GetCurrentBindedObject(DataGridView dgv) {
    2
    3 if (dgv == null || dgv.DataSource == null) {
    4 return null;
    5 }
    6
    7 BindingManagerBase bmb = dgv.BindingContext[dgv.DataSource];
    8
    9 if (bmb == null) {
    10 return null;
    11 }
    12
    13 return bmb.Current;
    14 }

    Il tipo di ritorno è un object che, in caso la sorgente dati sia una DataTable, dovrà essere castato a DataRowView.
    A questo punto, per accedere al dato che ci interessa leggere, possiamo usare il seguente codice:

    1    DataRowView drv = (DataRowView)GetCurrentBindedObject(dgvUsers); 
    2 string strNome = drv["Nome"].ToString();


    Il .NET Framework 2.0 però, ci permette di creare in modo semplice delle collection di oggetti bindabili ad elementi della UI.
    Usando questa nuova caratteristica ed i comodi Generics, possiamo modificare il codice di GetCurrentBindedObject per farci ritornare direttamente il tipo che ci interessa.
    Supponiamo di avere un oggetto User che rappresenta l’utente e la collection Users, che deriva da BinsingList<T> che rappresenta l’elenco dei nostri utenti (vedi codice allegato).
    Il nostro codice può essere modificato come segue:


    1    private T GetCurrentBindedObject(DataGridView dgv) where T: class {
    2
    3 if (dgv == null || dgv.DataSource == null) {
    4 return null;
    5 }
    6
    7 BindingManagerBase bmb = dgv.BindingContext[dgv.DataSource];
    8
    9 if (bmb == null) {
    10 return null;
    11 }
    12
    13 return bmb.Current as T;
    14 }


    da usare con il seguente codice:

    1    User user = GetCurrentBindedObject(dgvUsers);
    2 string Nome = user.Name;

     Lo stesso metodo, essendo generico, potrà essere usato per tutti gli object del nostro domain model.
    Il codice completo è disponibile nel file allegato.

    Posted Jun 30 2006, 11:36 PM by VitoA with 1 comment(s)
    Filed under:
  • Leggere il sorgente di una pagina html

    Autore: Vito Arconzo

    Ecco una funzione che restituisce il codice HTML di una pagina web.
     

    1        Function GetHtmlPageSource(ByVal url As String, _
    2                Optional ByVal username As String = Nothing, _
    3                Optional ByVal password As String = Nothing) As String
    4            Dim st As System.IO.Stream
    5            Dim sr As System.IO.StreamReader
    6    
    7            Try
    8                ' invia una Web request
    9                Dim req As System.Net.WebRequest = System.Net.WebRequest.Create(url)
    10   
    11               ' se sono specificati username/password usa le credenziali
    12               If Not username Is Nothing AndAlso Not password Is Nothing Then
    13                   req.Credentials = New System.Net.NetworkCredential(username, password)
    14               End If
    15   
    16               ' ricava la risposta e legge lo stream coi risultati
    17               Dim resp As System.Net.WebResponse = req.GetResponse
    18               st = resp.GetResponseStream
    19               sr = New System.IO.StreamReader(st)
    20   
    21               Return sr.ReadToEnd
    22           Catch ex As Exception
    23               Return ""
    24           Finally
    25               sr.Close()
    26               st.Close()
    27           End Try
    28       End Function
    
     
    Posted Jun 30 2006, 11:55 AM by VitoA with no comments
    Filed under:
More Posts Next page »
Powered by Community Server (Commercial Edition), by Telligent Systems