19 October 2010

Crea utente per tutti i db

Crea utente per tutti i db, facendo anche il mapping utente.
set nocount on

declare	#cur cursor for 
select	name
from	sys.databases
where database_id > 4
order by name

open #cur

declare @db as nvarchar(100)
fetch next from #cur into @db

declare @sq as nvarchar(max)
while @@fetch_status = 0
	begin
		set @sq = N'
USE [' + @db + ']
--CREATE USER [user.name] FOR LOGIN [user.name]
--EXEC sp_addrolemember N''db_owner'', N''user.name''
--DROP USER [user.name]
'

		print @sq
		exec sp_executesql @sq
		fetch next from #cur into @db
	end

close #cur
deallocate #cur

08 June 2010

SQL SERVER – Merge Operations – Insert, Update, Delete in Single Execution

This blog post is written in response to T-SQL Tuesday hosted by Jorge Segarra(aka SQLChicken).

 

I have been very active using these Merge operations in my development. However, I have found out from my consultancy work and friends that these amazing operations are not utilized by them most of the time. Here is my attempt to bring the necessity of using the Merge Operation to surface one more time.

MERGE is a new feature that provides an efficient way to do multiple DML operations. In earlier versions of SQL Server, we had to write separate statements to INSERT, UPDATE, or DELETE data based on certain conditions; however, at present, by using the MERGE statement, we can include the logic of such data changes in one statement that even checks when the data is matched and then just update it, and similarly, when the data is unmatched, it is inserted.

One of the most important advantages of MERGE statement is that the entire data are read and processed only once. In earlier versions, three different statements had to be written to process three different activities (INSERT, UPDATE or DELETE); however, by using MERGE statement, all the update activities can be done in one pass of database table.

I have written about these Merge Operations earlier in my blog post over here SQL SERVER – 2008 – Introduction to Merge Statement – One Statement for INSERT, UPDATE, DELETE. I was asked by one of the readers that how do we know that this operator was doing everything in single pass and was not calling this Merge Operator multiple times.

Let us run the same example which I have used earlier; I am listing the same here again for convenience.

--Let’s create Student Details and StudentTotalMarks and inserted some records.
USE tempdb
GO
CREATE TABLE StudentDetails
(
StudentID INTEGER PRIMARY KEY,
StudentName VARCHAR(15)
)
GO
INSERT INTO StudentDetails
VALUES(1,'SMITH')
INSERT INTO StudentDetails
VALUES(2,'ALLEN')
INSERT INTO StudentDetails
VALUES(3,'JONES')
INSERT INTO StudentDetails
VALUES(4,'MARTIN')
INSERT INTO StudentDetails
VALUES(5,'JAMES')
GO
CREATE TABLE StudentTotalMarks
(
StudentID INTEGER REFERENCES StudentDetails,
StudentMarks INTEGER
)
GO
INSERT INTO StudentTotalMarks
VALUES(1,230)
INSERT INTO StudentTotalMarks
VALUES(2,255)
INSERT INTO StudentTotalMarks
VALUES(3,200)
GO
-- Select from Table
SELECT *
FROM StudentDetails
GO
SELECT *
FROM StudentTotalMarks
GO
-- Merge Statement
MERGE StudentTotalMarks AS stm
USING (SELECT StudentID,StudentName FROM StudentDetails) AS sd
ON stm.StudentID = sd.StudentID
WHEN MATCHED AND stm.StudentMarks > 250 THEN DELETE
WHEN MATCHED THEN UPDATE SET stm.StudentMarks = stm.StudentMarks + 25
WHEN NOT MATCHED THEN
INSERT(StudentID,StudentMarks)
VALUES(sd.StudentID,25);
GO
-- Select from Table
SELECT *
FROM StudentDetails
GO
SELECT *
FROM StudentTotalMarks
GO
-- Clean up
DROP TABLE StudentDetails
GO
DROP TABLE StudentTotalMarks
GO

The Merge Join performs very well and the following result is obtained.

Let us check the execution plan for the merge operator. You can click on following image to enlarge it.

Let us evaluate the execution plan for the Table Merge Operator only.

We can clearly see that the Number of Executions property suggests value 1. Which is quite clear that in a single PASS, the Merge Operation completes the operations of Insert, Update and Delete.

I strongly suggest you all to use this operation, if possible, in your development. I have seen this operation implemented in many data warehousing applications.

 

Trovato qui.

17 May 2010

Cursore con “where current of”

set nocount on

-- CREO TABELLA TEMPORANEA ----------------------------------------------------
drop table #p

create table #p
(
 id int
)

insert #p values (10)
insert #p values (20)
insert #p values (30)
insert #p values (40)
insert #p values (50)
insert #p values (60)
insert #p values (70)
insert #p values (80)


select * from #p


-- DICHIARO IL CURSORE --------------------------------------------------------
declare @i int

declare #c cursor local for select id from #p

open #c

fetch next from #c into @i

while @@fetch_status = 0
 begin
  set @i = @i + 100
 
  update #p
  set id = @i
  where current of #c
 
  fetch next from #c into @i
 end


close #c
deallocate #c


select * from #p

Elimina file più vecchi di n giorni con ricorsione - BosoCleanDir.vbs / Delete old files

NOTE:
- impostare i parametri
- la riga che elimina i file è remmata

HACK:
- ottenere i parametri da commandline.

BosoCleanDir.vbs

' -- 2015-10-31 - aggiunto qualche echo()

Option Explicit

'------------------------------------------------------------------------------

' -- PARAMETRI
const elencoCartelle = "c:\test\1,c:\test\bla bla 2"
const maxGiorni = 30

'------------------------------------------------------------------------------

sub eliminaFile(wPath, oggi)
 
 if trim(wpath) = "" then exit sub
 
 with wscript
  .echo
  .echo "**** Processing directory: " & wpath
 end with

 dim wFileSystem, wFolder, wSubFolders, f, file
 set wFileSystem = createobject("Scripting.FileSystemObject")
 set wFolder = wFileSystem.getfolder(wPath)
 
 ' -- ELIMINA TUTTI I FILE PIU' VECCHI DI [maxGiorni] GIORNI
 for each file in wFolder.Files
  if DateDiff("d", file.DateCreated, oggi) > maxGiorni then
   wscript.echo "Deleting " & file.name
'   file.delete(true)
  end if
 next
 
 ' -- ELIMINA I FILES NELLE SOTTOCARTELLE
 dim subFolder
 for each subFolder in wFolder.SubFolders
  eliminaFile subFolder, oggi
 next

 set file = nothing
 set wFileSystem = nothing
 set wFolder = nothing
 Set wSubFolders = nothing
 
end sub

'------------------------------------------------------------------------------

sub Main()
 
 ' -- LOOP SULL'ELENCO DELLE CARTELLE
 dim arrFolder
 arrFolder = Split(elencoCartelle, ",")

 dim oggi
 oggi = now
 
 dim riga
 riga =  string(80, "*")
 
 with wscript
  .echo
  .echo riga
  .echo "* DELETING FILES OLDER THAN " & maxGiorni & " DAYS"
  .echo riga

  dim cartella
  for each cartella in arrFolder
   eliminaFile cartella, oggi
  next

  .echo
  .echo "** DONE"
 end with

end sub

'------------------------------------------------------------------------------

Main



Versione alternativa, senza output


Questa versione pulisce i log di IIS:
sLogFolder = "c:\inetpub\logs\LogFiles"
iMaxAge = 30   'in days

Set objFSO = CreateObject("Scripting.FileSystemObject")
set colFolder = objFSO.GetFolder(sLogFolder)

For Each colSubfolder in colFolder.SubFolders
        Set objFolder = objFSO.GetFolder(colSubfolder.Path)
        Set colFiles = objFolder.Files

        For Each objFile in colFiles
                iFileAge = now-objFile.DateCreated
                if iFileAge > (iMaxAge+1)  then
                        objFSO.deletefile objFile, True
                end if
        Next
Next

Via.

Chiudere la connessione dal DataReader

When you create a DataReader, you call .ExecuteDataReader. This method accepts a parameter that can be CommandBehavior.CloseConnection. This parameter tells the DataReader that when it is closed, the underlying connection should be closed as well. This is an example function that shows how you can return a DataReader and ensure that it is closed by the calling method:
// C# version

public static IDataReader SelectByRoyalty(int Percentage)
{ 
 SqlDataReader dr=null;
 SqlConnection cn=new SqlConnection
                  ("Server=Aron1;Database=pubs;Trusted_Connection=True;");
 cn.Open();
 try
 {
  SqlCommand cmd=new SqlCommand("byRoyalty",cn);
  cmd.CommandType=CommandType.StoredProcedure;
  cmd.Parameters.Add("@Percentage",Percentage);
   
  dr=cmd.ExecuteReader(CommandBehavior.CloseConnection);
 }
 catch ( Exception Ex )
 {
  if ( dr!=null )
  {
   dr.Close();
   cn.Close();
  }
  throw Ex;
 }
 return (IDataReader)dr;
}
' VB version

Public Shared Function SelectByRoyalty(ByVal Percentage As Integer) As IDataReader
    Dim dr As SqlDataReader = Nothing
    Dim cn As New SqlConnection("Server=Aron1;Database=pubs;Trusted_Connection=True;")
    cn.Open()
    Try
        Dim cmd As New SqlCommand("byRoyalty", cn)
        cmd.CommandType = CommandType.StoredProcedure
        cmd.Parameters.Add("@Percentage", Percentage)

        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    Catch Ex As Exception
        If dr <> Nothing Then
            dr.Close()
            cn.Close()
        End If
        Throw Ex
    End Try
    Return DirectCast(dr, IDataReader)
End Function
Then, you could call the method as follows:
IDataReader dr=Coatings.SelectCoating(CoatingID);
try
{
 // Use the DataReader..
}
Finally
{
 dr.Close();
}
Failure to use a pattern like this will lead to a great deal of difficulty with connections that are not closed in a timely fashion. I believe that Microsoft initially pushed DataReaders as the preferred way to do database access, at least for ASP.NET applications. As time went on, I think the company discovered that many developers misused DataReaders, not properly closing the connection. Recent Microsoft presentations have often emphasized DataSets even for ASP.NET applications.

Cerca opzioni database su un server

-- This script works well in SQL 2000, didn't test in 2005+) 

DECLARE @DataBase sysname 

DECLARE	database_cursor CURSOR FOR 
SELECT	quotename(name) as Base 
FROM 	master..sysdatabases 
WHERE	DATABASEPROPERTYEX(name, 'Status') = 'ONLINE' AND 
		DATABASEPROPERTYEX(name, 'IsAutoShrink') = 1 

OPEN database_cursor 

FETCH NEXT 
FROM database_cursor 
INTO @DataBase 

WHILE @@FETCH_STATUS = 0 
	BEGIN 
		PRINT @DataBase
--		EXEC ('ALTER DATABASE ' + @DataBase + ' SET AUTO_SHRINK OFF') 

		FETCH NEXT 
		FROM database_cursor 
		INTO @DataBase 
	END 

CLOSE database_cursor 
DEALLOCATE database_cursor 
GO 

Apri UI stampa attendendo esecuzione comando

Dim WshShell, oExec
dim wCmd


' COMANDO DA ESEGUIRE
wCmd = "rundll32 printui.dll,PrintUIEntry /o /n\\nome_macchina\nome_stampante"


' CREA L'OGGETTO SHELL (PER LANCIARE IL COMANDO)
set WshShell = CreateObject("WScript.Shell")


' ESEGUE IL COMANDO
set oExec = WshShell.Exec(wcmd)


' ATTENDE IL TERMINE DELL'ESECUZIONE DEL COMANDO
Do While oExec.Status = 0
	WScript.Sleep 100
Loop


' ESECUZIONE TERMINATA!
MsgBox oExec.Status


' SVUOTA OGGETTI (PER "RISPARMIARE" MEMORIA)
set WshShell = nothing
set oExec = nothing

Conversione di codice html in testo piano

Piccolo e utile frammento di codice che, utilizzando le amate/odiate espressioni regolari, ripulisce dai tag html il testo passato.

 

Imports System.Text
Imports System.Text.RegularExpressions
		
Function Html2Text(ByVal html As String) As String
 
   Dim repattern As String = “\<[^\>]*\>“
   Dim rexp As New Regex(repattern, RegexOptions.IgnoreCase)

    html = rexp.Replace(html, String.Empty)

   Return html
End Function

sp_who filtrata

set nocount on

drop table #boso

create table #boso
(
	spid nvarchar(max), 
	ecid nvarchar(max), 
	status nvarchar(max), 
	loginame nvarchar(max), 
	hostname nvarchar(max), 
	blk nvarchar(max), 
	dbname nvarchar(max), 
	cmd nvarchar(max), 
	request_id nvarchar(max)
)

insert #boso
exec sp_who


select * 
from #boso
where dbname = 'ITPORTAL_FALCONE'
order by status

Accesso ai dati asincrono – Async data access

Namespace DotNetSide.Articles.AsyncDataAccess
    Imports System
    Imports System.Collections.Generic
    Imports System.ComponentModel
    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Drawing
    Imports System.Text
    Imports System.Windows.Forms
    
    
    Public Class Form1
        Inherits Form
        
        Public Sub New()
            MyBase.New
            InitializeComponent
        End Sub
        
        Private Sub btnStart_Click(ByVal sender As Object, ByVal e As EventArgs)
            Dim myConnection As SqlConnection = New SqlConnection
            myConnection.ConnectionString = "Data Source=.\\SQLEXPRESS;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=ProgrammareADONet;async=true"
            myConnection.Open
            Dim cmd As SqlCommand = myConnection.CreateCommand
            cmd.CommandText = "WaitFor Delay '00:00:15' Select @@Version"
            cmd.BeginExecuteReader(New AsyncCallback(ProcessResult), cmd)
        End Sub
        
        Public Sub ProcessResult(ByVal asyncRes As IAsyncResult)
            Dim cmd As SqlCommand = CType(asyncRes.AsyncState,SqlCommand)
            cmd.Connection
            cmd
            Dim DBVersion As String = string.Empty
            Dim myReader As SqlDataReader = cmd.EndExecuteReader(asyncRes)
            If myReader.Read Then
                DBVersion = myReader(0).ToString
                lbltextVersion.BeginInvoke(New LabelHnd(Update), DBVersion)
            End If
        End Sub
        
        Public Sub Update(ByVal text As String)
            lbltextVersion.Text = text
        End Sub
        
        Public Delegate Sub LabelHnd(ByVal value As String)
    End Class
End Namespace

Apri Access da .NET

' Apre una form in un db di AccessForm, passando la WhereCondition
Private Sub ApriAccess()

Try
        Console.WriteLine("premi un tasto per aprire access...")
        Console.ReadKey()

        Dim a As New Access.Application

        a.OpenCurrentDatabase("d:\pippo.mdb")
        a.DoCmd.OpenForm("Form1", , , " Nome='C' ")
        a.Visible = True

        Console.WriteLine("premi un tasto per chiudere access...")
    	Console.ReadKey()
    	
        a.CloseCurrentDatabase()
    Catch ex As Exception

    End Try

    a = Nothing

End Sub

Cerca campi orfani fra due tabelle

create procedure sys_CampiOrfani_sp
	@tab1 as nvarchar(100), 
	@tab2 as nvarchar(100)
AS
BEGIN
	set nocount on

	select	c.*, s.name as typeName
	into	#aaa
	from	sys.columns c inner join sys.types s on 
			c.system_type_id = s.system_type_id
	where	c.object_id = object_id(@tab1)


	select	c.*, s.name as typeName
	into	#bbb
	from	sys.columns c inner join sys.types s on 
			c.system_type_id = s.system_type_id
	where	c.object_id = object_id(@tab2)


	select	@tab1 AS 'Table name', a.name AS 'Nome campo', a.typeName, 
			a.max_length, a.precision, a.scale
	from	#aaa a LEFT join #bbb b on 
			a.name = b.name
	where	b.name is null
	order by
			a.name


	select	@tab2 AS 'Table name', b.name AS 'Nome campo', b.typeName, 
			b.max_length, b.precision, b.scale
	from	#aaa a RIGHT join #bbb b on 
			a.name = b.name
	where	a.name is null
	order by
			b.name

END

go

exec sys_CampiOrfani_sp 
'MPS_InterventiStorico',
'RichiesteManutenzione_tb'

if object_id('sys_CampiOrfani_sp') is not null 
	drop procedure sys_CampiOrfani_sp

13 May 2010

SQL CSV to Table

ALTER Function [dbo].[Csv2Table_fn] (@CSVList nvarchar(1000))
 RETURNS @Table table (id nvarchar(50))
AS
BEGIN
 DECLARE @sep AS nvarchar(1); SET @sep = ','
 
 IF RIGHT(@CSVList, 1) <> @sep SET @CSVList = @CSVList + @sep

 DECLARE @Pos smallint; SET @Pos = 1
 DECLARE @OldPos smallint; SET @OldPos = 1
 
 WHILE @Pos < LEN(@CSVList)
  BEGIN
   SET @Pos = CHARINDEX(@sep, @CSVList, @OldPos)
   
   INSERT @Table
   SELECT LTRIM(RTRIM(SUBSTRING(@CSVList, @OldPos, @Pos - @OldPos)))
   
   SET @OldPos = @Pos + 1
  END

 RETURN
END
GO

-- ESEMPIO:
DECLARE @S AS NVARCHAR(100)
SET @S = 'ROSSO, VERDE,BLU,   BOSO'
SELECT * FROM CSVToTable_fn(@S)



VERSIONE CON SEPARATORE PARAMETRICO:
CREATE FUNCTION [dbo].[Csv2Table_fn]
(
   @CSVList nvarchar(MAX)
 , @sep nvarchar(1) = ','
)
 RETURNS @Table table (id nvarchar(50))
AS
BEGIN 
 IF RIGHT(@CSVList, 1) <> @sep SET @CSVList = @CSVList + @sep

 DECLARE @Pos smallint; SET @Pos = 1
 DECLARE @OldPos smallint; SET @OldPos = 1
 
 WHILE @Pos < LEN(@CSVList)
  BEGIN
   SET @Pos = CHARINDEX(@sep, @CSVList, @OldPos)
   
   INSERT @Table
   SELECT LTRIM(RTRIM(SUBSTRING(@CSVList, @OldPos, @Pos - @OldPos)))
   
   SET @OldPos = @Pos + 1
  END

 RETURN
END
GO
UTILIZZATO PER SPLITTARE UNA STRINGA:
DECLARE @split table (Id nvarchar(50), Posizione int)
 
INSERT @split (Id, Posizione)
SELECT Id, ROW_NUMBER() OVER (ORDER BY GETDATE()) - 1
FROM GVSYS..Csv2Table_fn('38023454.XZQ.QWE.00029466.0768.txt', '.')


SELECT *
FROM @split s



-- RISULTATO:

Id     Posizione
---------------------
38023454            0
XZQ                 1
QWE                 2
00029466            3
0768                4
txt                 5

Trovato qui.

COPY/XCOPY from network: restartable mode

I recently had to copy a very large file (>4GB) from a remote Windows share to my Windows 7 machine, over a very finicky connection (frequently-failing VPN over a slow Internet connection). A GUI copy didn't work because the connection dropped frequently. Then a colleague pointed me to the "copy /z" command:
/Z Copies networked files in restartable mode.
And this simple, built-in tool turned out to be the thing I needed. It was, every time, able to restart the download properly, and after a few times, it downloaded the file correctly.
A couple of tips:
  • If you interrupt the command with Ctrl-C, it will delete the portion copied so far and you'll have to restart the copy from the beginning. If you must interrupt a copy, simply terminate the network connection (it will die with an error, but leave the copied-so-far file) or close the window where the command is running.
  • When you restart it and it asks if you want to overwrite, you must answer "yes". You can also use the /Y flag.

Trovato qui.

05 May 2010

Rinumera record con una sola update

IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
 DROP TABLE #tmp

SELECT IdArgomento, IdPagina, OrdineVis 
INTO #tmp 
FROM PagineArgomenti_tb 
WHERE IdArgomento = 171 
ORDER BY OrdineVis 


DECLARE @Newpos smallint
SELECT @Newpos = 0


UPDATE #tmp 
SET  @Newpos = OrdineVis = @Newpos + 10 


UPDATE p
SET  p.OrdineVis = t.OrdineVis 
FROM PagineArgomenti_tb p 
  INNER JOIN #tmp t 
   ON p.IdArgomento = t.IdArgomento 
   AND p.IdPagina = t.IdPagina



Oppure, con la funzione ROW_NUMBER()
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
 DROP TABLE #tmp

SELECT IdArgomento, IdPagina, ROW_NUMBER() OVER (ORDER BY OrdineVis) AS OrdineVis 
INTO #tmp 
FROM PagineArgomenti_tb 
WHERE IdArgomento = 171 


UPDATE p
SET  p.OrdineVis = t.OrdineVis 
FROM PagineArgomenti_tb p 
  INNER JOIN #tmp t 
   ON p.IdArgomento = t.IdArgomento 
   AND p.IdPagina = t.IdPagina

L'ORDER BY è dentro la OVER().
Se voglio un progressivo e basta, si può fare ROW_NUMBER() OVER (ORDER BY GETDATE())

29 April 2010

The 10/20/30 Rule of PowerPoint

It’s quite simple: a PowerPoint presentation should have ten slides, last no more than twenty minutes, and contain no font smaller than thirty points. While I’m in the venture capital business, this rule is applicable for any presentation to reach agreement: for example, raising capital, making a sale, forming a partnership, etc.
  • Ten slides. Ten is the optimal number of slides in a PowerPoint presentation because a normal human being cannot comprehend more than ten concepts in a meeting—and venture capitalists are very normal. (The only difference between you and venture capitalist is that he is getting paid to gamble with someone else’s money). If you must use more than ten slides to explain your business, you probably don’t have a business. The ten topics that a venture capitalist cares about are:
    1. Problem
    2. Your solution
    3. Business model
    4. Underlying magic/technology
    5. Marketing and sales
    6. Competition
    7. Team
    8. Projections and milestones
    9. Status and timeline
    10. Summary and call to action
  • Twenty minutes. You should give your ten slides in twenty minutes. Sure, you have an hour time slot, but you’re using a Windows laptop, so it will take forty minutes to make it work with the projector. Even if setup goes perfectly, people will arrive late and have to leave early. In a perfect world, you give your pitch in twenty minutes, and you have forty minutes left for discussion.
  • Thirty-point font. The majority of the presentations that I see have text in a ten point font. As much text as possible is jammed into the slide, and then the presenter reads it. However, as soon as the audience figures out that you’re reading the text, it reads ahead of you because it can read faster than you can speak. The result is that you and the audience are out of synch.
    The reason people use a small font is twofold: first, that they don’t know their material well enough; second, they think that more text is more convincing. Total bozosity. Force yourself to use no font smaller than thirty points. I guarantee it will make your presentations better because it requires you to find the most salient points and to know how to explain them well. If “thirty points,” is too dogmatic, the I offer you an algorithm: find out the age of the oldest person in your audience and divide it by two. That’s your optimal font size.
So please observe the 10/20/30 Rule of PowerPoint. If nothing else, the next time someone in your audience complains of hearing loss, ringing, or vertigo, you’ll know what caused the problem. One last thing: to learn more about the zen of great presentations, check out a site called Presentation Zen by my buddy Garr Reynolds.
Trovato qui.

26 April 2010

#1016 Trasformazione di Web.Config in Visual Studio 2010

  di Marco De Sanctis
http://www.aspitalia.com/script/1016/Sharp1016-Trasformazione-Web.Config-Visual-Studio-2010.aspx


Tra le novità di Visual Studio 2010, una estremamente utile riguarda la possibilità di gestire differenti file di configurazione grazie a Web Config Transformation, che consiste in un semplice linguaggio di scripting tramite il quale indicare come il file Web.Config che utilizziamo nel nostro ambiente di sviluppo debba essere rielaborato prima di essere distribuito.
Supponiamo ad esempio che la nostra applicazione si interfacci al database Northwind tramite questa stringa di connessione che, come possiamo notare, punta ad un database locale utilizzando l'autenticazione di Windows.

<add name="Northwind"
    connectionString="server=.;database=Northwind;Integrated Security=SSPI"/>


Tipicamente abbiamo diverse impostazioni di questo tipo, che oltre al database possono riguardare log, posta elettronica, pagine di errore personalizzate, e che ogni volta che effettuiamo un deployment completo siamo costretti a modificare manualmente.
Con Visual Studio 2010, se espandiamo il file Web.Config su Solution Explorer possiamo notare la presenza di ulteriori due file, che contengono le trasformazioni necessarie per le configurazioni Debug e Release.
Ovviamente, se la nostra solution dovesse possedere ulteriori configurazioni, ad esempio Test o Staging, è possibile creare le relative trasformazioni selezionando la voce Add Config Transforms dal menu contestuale che si apre su Web.Config.
Il contenuto di questi file è simile ad un normale Web.Config, a parte la dichiarazione di un particolare namespace xml che abilita l'utilizzo dei tag di trasformazione.

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
...
</configuration>

Supponiamo allora di voler modificare il Web.Config generato in Release in modo che la stringa di connessione Northwind sia quella relativa al database di produzione. Ciò che possiamo fare è indicarne la trasformazione all'interno del file Web.Release.Config come segue:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
 <connectionStrings>
   <add name="Northwind"
        connectionString="server=productionServer;database=Northwind;username=test;password=pwd"
        xdt:Locator="Match(name)" xdt:Transform="Replace"/>
 </connectionStrings>
</configuration>


I due nuovi tag xdt:Locator e xdt:Transform consentono di specificare come la trasformazione deve avvenire, e in particolare:
- xdt:Locator rappresenta la modalità secondo cui deve essere individuata la stringa di connessione da trasformare, nel nostro caso con Match(name) abbiamo indicato che la ricerca deve essere effettuata in base al valore dell'attributo name;
- xdt:Transform rappresenta invece la trasformazione vera e propria, nel nostro caso abbiamo specificato Replace per indicare che la stringa di connessione Northwind sul file originale dovrà essere sostituita con quella corrente.

L'elenco completo di tutte le funzionalità di questi due tag è disponibile a questo indirizzo:
http://msdn.microsoft.com/en-us/library/dd465326.aspx
Se a questo punto generiamo il pacchetto di installazione (Project -> Build Deployment Package) o effettuiamo la pubblicazione della nostra Web Application (Build -> Publish Web Application) in configurazione Release, al Web.Config originale saranno automaticamente applicate le trasformazioni specificate.
Se pensiamo al fatto che, grazie alle nuove modalità di pubblicazione di Visual Studio 2010, è possibile fare in modo che avvenga in automatico anche l'upload del pacchetto di installazione sul server in hosting e la registrazione in IIS, ci possiamo subito rendere conto di come sia potente questo nuovo strumento, grazie al quale possiamo a tutti gli effetti gestire diversi scenari di deployment con pochissimi click del mouse.

14 April 2010

Inserire testo random in Word / Lorem Ipsum generator

You need to write the same function in Word as;

=rand()

On pressing enter, you will see the auto-fill paragraph.

 rand

Another place holding text filler which has been widely used in web designing and other prototypes is;

Lorem ipsum dolor sit amet, consectetur adipisicing elit……

For filling Word document with this placeholder filler, you need write it as

=lorem()

 lorem

 

Note:

  • Testato in Word 2007
  • Alle funzioni si può passare un parametro numerico (la lunghezza del testo??).

Trovato qui.

31 March 2010

How To: Use Regular Expressions to Constrain Input in ASP.NET

patterns & practices Developer Center
J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley
Microsoft Corporation
May 2005

Applies To

  • ASP.NET version 1.0
  • ASP.NET version 1.1
  • ASP.NET version 2.0

Summary

This How To shows how you can use regular expressions within ASP.NET applications to constrain untrusted input. Regular expressions are a good way to validate text fields such as names, addresses, phone numbers, and other user information. You can use them to constrain input, apply formatting rules, and check lengths. To validate input captured with server controls, you can use the RegularExpressionValidator control. To validate other forms of input, such as query strings, cookies, and HTML control input, you can use the System.Text.RegularExpressions.Regex class.
This How To shows how you can use regular expressions within ASP.NET applications to constrain untrusted input.

Contents

Objectives
Overview
Using a RegularExpressionValidator Control
Using the Regex Class
Common Regular Expressions
Additional Resources

Objectives

  • Use regular expressions to constrain input, apply format rules, and check lengths.
  • Use the ASP.NET RegularExpressionValidator control to constrain and validate input.
  • Use the Regex class to constrain and validate input.
  • Learn common regular expressions that can be used to constrain input.

Overview

If you make unfounded assumptions about the type, length, format, or range of input, your application is unlikely to be robust. Input validation can become a security issue if an attacker discovers that you have made unfounded assumptions. The attacker can then supply carefully crafted input that compromises your application by attempting SQL injection, cross-site scripting, and other injection attacks. To avoid such vulnerability, you should validate text fields (such as names, addresses, tax identification numbers, and so on) and use regular expressions to do the following:
  • Constrain the acceptable range of input characters.
  • Apply formatting rules. For example, pattern-based fields, such as tax identification numbers, ZIP Codes, or postal codes, require specific patterns of input characters.
  • Check lengths.
Regular expression support is available to ASP.NET applications through the RegularExpressionValidator control and the Regex class in theSystem.Text.RegularExpressions namespace.

Using a RegularExpressionValidator Control

If you capture input by using server controls, you can use the RegularExpressionValidator control to validate that input. You can use regular expressions to restrict the range of valid characters, to strip unwanted characters, and to perform length and format checks. You can constrain the input format by defining patterns that the input must match.
To validate a server control's input using a RegularExpressionValidator
  1. Add a RegularExpressionValidator control to your page.
  2. Set the ControlToValidate property to indicate which control to validate.
  3. Set the ValidationExpression property to an appropriate regular expression.
  4. Set the ErrorMessage property to define the message to display if the validation fails.
The following example shows a RegularExpressionValidator control used to validate a name field.

<%@ language="C#" %>
<form id="form1" runat="server">
    <asp:TextBox ID="txtName" runat="server"/>
    <asp:Button ID="btnSubmit" runat="server" Text="Submit" />
    <asp:RegularExpressionValidator ID="regexpName" runat="server"     
                                    ErrorMessage="This expression does not validate." 
                                    ControlToValidate="txtName"     
                                    ValidationExpression="^[a-zA-Z'.\s]{1,40}$" />
</form>
The regular expression used in the preceding code example constrains an input name field to alphabetic characters (lowercase and uppercase), space characters, the single quotation mark (or apostrophe) for names such as O'Dell, and the period or dot character. In addition, the field length is constrained to 40 characters.
Using ^ and $
Enclosing the expression in the caret (^) and dollar sign ($)markers ensures that the expression consists of the desired content and nothing else. A ^matches the position at the beginning of the input string and a $ matches the position at the end of the input string. If you omit these markers, an attacker could affix malicious input to the beginning or end of valid content and bypass your filter.

Using the Regex Class

If you are not using server controls (which means you cannot use the validation controls) or if you need to validate input from sources other than form fields, such as query string parameters or cookies, you can use the Regex class within the System.Text.RegularExpressions namespace.
To use the Regex class
  1. Add a using statement to reference the System.Text.RegularExpressions namespace.
  2. Call the IsMatch method of the Regex class, as shown in the following example.
    // Instance method:
    Regex reg = new Regex(@"^[a-zA-Z'.]{1,40}$");
    Response.Write(reg.IsMatch(txtName.Text));
    
    // Static method:
    if (!Regex.IsMatch(txtName.Text, 
                       @"^[a-zA-Z'.]{1,40}$"))
    {
      // Name does not match schema
    }
For performance reasons, you should use the static IsMatch method where possible to avoid unnecessary object creation.
The following example shows how to use a regular expression to validate a name input through a regular client-side HTML control.

<%@ Page Language="C#" %>

<html xmlns="http://www.w3.org/1999/xhtml" >
  <body>
    <form id="form1" method="post" action="HtmlControls.aspx">
        Name:
        <input name="txtName" type="text" />
        <input name="submitBtn" type="Submit" value="Submit"/>
    </form>
  </body>
</html>

<script runat="server">

  void Page_Load(object sender, EventArgs e)
  {
    if (Request.RequestType == "POST")
    {
      string name = Request.Form["txtName"];
      if (name.Length > 0)
      {
        if (System.Text.RegularExpressions.Regex.IsMatch(name, 
                                           "^[a-zA-Z'.]{1,40}$"))
          Response.Write("Valid name");
        else
          Response.Write("Invalid name");
      }
    }
  }

</script>
Use Regular Expression Comments
Regular expressions are much easier to understand if you use the following syntax and comment each component of the expression by using a number sign (#). To enable comments, you must also specify RegexOptions.IgnorePatternWhitespace, which means that non-escaped white space is ignored.

Regex regex = new Regex(@"
                        ^           # anchor at the start
                       (?=.*\d)     # must contain at least one numeric character
                       (?=.*[a-z])  # must contain one lowercase character
                       (?=.*[A-Z])  # must contain one uppercase character
                       .{8,10}      # From 8 to 10 characters in length
                       \s           # allows a space 
                       $            # anchor at the end", 
                       RegexOptions.IgnorePatternWhitespace);

Common Regular Expressions

Some common regular expressions are shown in Table 1.
Table 1. Common Regular Expressions
Field Expression Format Samples Description
Name ^[a-zA-Z''-'\s]{1,40}$ John Doe
O'Dell
Validates a name. Allows up to 40 uppercase and lowercase characters and a few special characters that are common to some names. You can modify this list.
Social Security Number ^\d{3}-\d{2}-\d{4}$ 111-11-1111 Validates the format, type, and length of the supplied input field. The input must consist of 3 numeric characters followed by a dash, then 2 numeric characters followed by a dash, and then 4 numeric characters.
Phone Number ^[01]?[- .]?(\([2-9]\d{2}\)|[2-9]\d{2})[- .]?\d{3}[- .]?\d{4}$ (425) 555-0123
425-555-0123
425 555 0123
1-425-555-0123
Validates a U.S. phone number. It must consist of 3 numeric characters, optionally enclosed in parentheses, followed by a set of 3 numeric characters and then a set of 4 numeric characters.
E-mail ^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$ someone@example.com Validates an e-mail address.
URL ^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?$ http://www.microsoft.com Validates a URL
ZIP Code ^(\d{5}-\d{4}|\d{5}|\d{9})$|^([a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d)$ 12345 Validates a U.S. ZIP Code. The code must consist of 5 or 9 numeric characters.
Password (?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,10})$ Validates a strong password. It must be between 8 and 10 characters, contain at least one digit and one alphabetic character, and must not contain special characters.
Non- negative integer ^\d+$ 0
986
Validates that the field contains an integer greater than zero.
Currency (non- negative) ^\d+(\.\d\d)?$ 1.00 Validates a positive currency amount. If there is a decimal point, it requires 2 numeric characters after the decimal point. For example, 3.00 is valid but 3.1 is not.
Currency (positive or negative) ^(-)?\d+(\.\d\d)?$ 1.20 Validates for a positive or negative currency amount. If there is a decimal point, it requires 2 numeric characters after the decimal point.

Additional Resources
For more information, see the regular expression tutorial at http://www.regular-expressions.info/tutorial.html.

 
Trovato qui.

25 March 2010

Tronca i log e compatta tutti i database (Sql2005)

Versione sia per Sql2000 che per Sql2005:
-- TRONCA I LOG E COMPATTA TUTTI I DATABASE
set nocount on


USE master
GO

EXEC sp_msForEachDB '
BACKUP LOG [?] WITH TRUNCATE_ONLY
DBCC SHRINKDATABASE (''?'', TRUNCATEONLY) WITH NO_INFOMSGS
'

Versione con cursore per Sql2005:
-- TRONCA I LOG E COMPATTA TUTTI I DATABASE ONLINE
-- VERSIONE PER SQL 2005
USE master
GO

set nocount on

declare	cur cursor for
select	name
from	sys.databases
where	database_id > 4 and
		state_desc = 'ONLINE'
order by 
		name

open cur

declare @nomeDB as nvarchar(255)

fetch next from cur into @nomedb

while @@fetch_status = 0 
begin
	print 'Processing ' + @nomeDB + '...'
	
	BACKUP LOG @nomeDB WITH TRUNCATE_ONLY
	DBCC SHRINKDATABASE (@nomeDB, TRUNCATEONLY) WITH NO_INFOMSGS

	fetch next from cur into @nomedb
end


close cur
deallocate cur

print ''
print 'Done.'

23 March 2010

Realizzare un AdRotator lato client con ASP.NET e jQuery

Il controllo AdRotator risulta utile tutte le volte in cui vogliamo visualizzare una serie banner pubblicitari in pagina, ma ha il problema di aggiornare il proprio contenuto solo in risposta ad un postback; ciò lo rende di fatto poco utilizzabile in scenari basati su AJAX o su applicazioni Silverlight, dato che in questi casi il numero di banner visualizzati diminuirebbe drasticamente a causa dei pochi refresh di pagina.
In contesti simili è possibile implementare una logica analoga sfruttando jQuery per invocare un servizio remoto e aggiornare l'interfaccia della pagina. Supponiamo allora di aver implementato, lato server, un metodo in grado di recuperare il prossimo banner da visualizzare:
[WebMethod]
public static string GetNextAdvertisement() 
{ 
    var rnd = new Random(DateTime.Now.Millisecond); 
    int index = rnd.Next(1, 5); 

    var serializer = new JavaScriptSerializer(); 
    return serializer.Serialize(new 
    { 
        ImageUrl = string.Format("images/Banner{0}.png", index), 
        Url = string.Format("advertisement.ashx?idx={0}", index) 
    }); 
}


Nel nostro esempio, la logica utilizzata per determinare il risultato è basata su numeri casuali, ma in uno scenario reale è possibile ovviamente implementare funzionalità più complesse, che accedano ad un database per recuperare un elenco di inserzionisti e memorizzino il numero di visualizzazioni di ogni banner. Il risultato è comunque un oggetto che contiene due proprietà ImageUrl e Url, serializzato in formato JSON utilizzando ilJavaScriptSerializer.
Grazie all'attributo WebMethod, questo metodo viene esposto da ASP.NET come un servizio ed è invocabile lato client tramite una chiamata AJAX simile alla seguente:


function askForNewBanner() { 
$.ajax({
url: "default.aspx/GetNextAdvertisement",
type: "POST",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) { updateBanner(data.d); }
});
}


La funzione askForNewBanner utilizza il metodo jQuery.ajax per effettuare la chiamata remota al servizio. Esso consente di specificare un gran numero di parametri secondo cui deve avvenire la comunicazione; senza entrare troppo nei dettagli, nel nostro esempio l'URL è dato dall'indirizzo della pagina seguito dal nome del metodo. Quando l'invocazione si conclude con successo, il risultato ottenuto viene passato alla funzioneupdateBanner che deve effettivamente occuparsi di modificare il markup HTML.
In pagina il banner è realizzato con un div che contiene un link e un'immagine:


<div id="adv" style="visibility:hidden"> 
<a href="#">
<img src="" alt="adv" />
</a>
</div>


La funzione updateBanner è in grado di modificarne il contenuto a partire dalla stringa JSON fornita in input:


function updateBanner(data) { 
var obj = $.parseJSON(data);
$('#adv a').attr("href", obj.Url);
$('#adv a img').attr("src", obj.ImageUrl);
$('#adv').css("visibility", "visible");
}


Tramite il metodo jQuery.parseJSON, infatti, è possibile convertire una stringa JSON valida in un vero e proprio oggetto Javascript, che possiamo poi utilizzare per modificare il contenuto dell'immagine e impostare il relativo link.
Fino ad ora, insomma, siamo riusciti a realizzare un'infrastruttura client che interroga un servizio remoto e visualizza un banner pubblicitario in pagina in base alla risposta ottenuta. A questo punto non resta che temporizzarne l'esecuzione, in modo che gli inserzionisti possano essere effettivamente ruotati anche senza che avvengano refresh di pagina, ad esempio utilizzando il plugin jQuery Timers per mostrarne uno diverso ogni 30 secondi:


$(function() { 
askForNewBanner();
$(document).everyTime("30s", function() {
askForNewBanner();
});
});



Trovato qui

22 March 2010

Speed Up Windows 7 Taskbar Navigation with a Registry Hack

The fundamental problem was that you needed two clicks to navigate to your document if you have two instances of a program running. Or you're stuck with hovering for what feels like an eternity.

At Windows 7 Forums I finally found a nice step in the right direction. Full post is here, but summarized below. In short, this hack causes an applications last active window to activate when you click the taskbar icon, and the next window in the second click, etc. The hover preview still works if you hover to begin with, but if you want the preview after you've click on an app's icon in the taskbar, you can Ctrl+Click to bring it back. The current default settings are the exact opposite (that is, Ctrl+Click cycles through the last active windows of an application).

  • Launch regedit.exe
  • Navigate in the left tree control to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
  • Go to Edit->New->DWORD (32-bit) Value
  • Name the value LastActiveClick
  • Hit enter to assign the value and change it to 1
  • Restart Explorer and you're good to go.

To restart Explorer without rebooting, open the Task Manager (Ctrl+Shift+Esc) and end the Explorer.exe process. Then create a new task (under "File") and paste "explorer.exe".

19 March 2010

How To Replace Notepad in Windows 7

It used to be that Notepad was a necessary evil because it started up quickly and let us catch a quick glimpse of plain text files. Now, there are a bevy of capable Notepad replacements that are just as fast, but also have great feature sets.
Before following the rest of this how-to, ensure that you’re logged into an account with Administrator access.
Note: The following instructions involve modifying some Windows system folders. Don’t mess anything up while you’re in there! If you follow our instructions closely, you’ll be fine.
Choose your replacement
There are a ton of great Notepad replacements, including Notepad2, Metapad, and Notepad++. The best one for you will depend on what types of text files you open and what you do with them. We’re going to use Notepad++ in this how-to.
The first step is to find the executable file that you’ll replace Notepad with. Usually this will be the only file with the .exe file extension in the folder where you installed your text editor. Copy the executable file to your desktop and try to open it, to make sure that it works when opened from a different folder.
In the Notepad++ case, a special little .exe file is available for the explicit purpose of replacing Notepad.If we run it from the desktop, it opens up Notepad++ in all its glory.
sshot-1
Back up Notepad
You will probably never go back once you switch, but you never know. You can backup Notepad to a special location if you’d like, but we find it’s easiest to just keep a backed up copy of Notepad in the folders it was originally located.
In Windows 7, Notepad resides in:
  • C:\Windows
  • C:\Windows\System32
  • C:\Windows\SysWOW64 in 64-bit versions only
Navigate to each of those directories and copy Notepad.
sshot-2
Paste it into the same folder.
sshot-3
If prompted, choose to Copy, but keep both files.
sshot-4
You can keep your backup as “notepad (2).exe”, but we prefer to rename it to “notepad.exe.bak”.
sshot-6
Do this for all of the folders that have Notepad (2 total for 32-bit Windows 7, 3 total for 64-bit).
Take control of Notepad and delete it
Even if you’re on an administrator account, you can’t just delete Notepad – Microsoft has made some security gains in this respect. Fortunately for us, it’s still possible to take control of a file and delete it without resorting to nasty hacks like disabling UAC.
Navigate to one of the directories that contain Notepad. Right-click on it and select Properties.
sshot-7
Switch to the Security tab, then click on the Advanced button.
sshot-8
Note that the owner of the file is a user called “TrustedInstaller”.
sshot-9
You can’t do much with files owned by TrustedInstaller, so let’s take control of it. Click the Edit… button. Select the desired owner (you could choose your own account, but we’re going to give any Administrator control) and click OK.
sshot-10
You’ll get a message that you need to close and reopen the Properties windows to edit permissions. Before doing that, confirm that the owner has changed to what you selected.
sshot-11
Click OK, then OK again to close the Properties window. Right-click on Notepad and click on Properties again.
Switch to the Security tab. Click on Edit….
sshot-12
Select the appropriate group or user name in the list at the top, then add a checkmark in the checkbox beside Full control in the Allow column.
sshot-14
Click OK, then Yes to the dialog box that pops up.
sshot-15
Click OK again to close the Properties window.
Now you can delete Notepad, by either selecting it and pressing Delete on the keyboard, or right-click on it and click Delete.
sshot-16
You’re now free from Notepad’s foul clutches!
sshot-17
Repeat this procedure for the remaining folders (or folder, on 32-bit Windows 7).
Drop in your replacement
Copy your Notepad replacement’s executable, which should still be on your desktop.
sshot-18
Browse to the two or three folders listed above and copy your .exe to those locations. If prompted for Administrator permission, click Continue.
sshot-19
If your executable file was named something other than “notepad.exe”, rename it to “notepad.exe”. Don’t be alarmed if the thumbnail still shows the old Notepad icon.
sshot-20
Double click on Notepad and your replacement should open.
sshot-21
To make doubly sure that it works, press Win+R to bring up the Run dialog box and enter “notepad” into the text field. Press enter or click OK.
sshot-22
sshot-23
Now you can allow Windows to open files with Notepad by default with little to no shame! All without restarting or having to disable UAC!

18 March 2010

Downlad a web page – Scaricare una pagina web – Iron AdBlock.ini update

option explicit

' -----------------------------------------------------------------------------
' PARAMETERS
' -----------------------------------------------------------------------------
const source = "http://fanboy.co.nz/adblock/iron/adblock.ini"
const destination = "C:\Program Files (x86)\SRWare Iron\adblock.ini"
' -----------------------------------------------------------------------------


UpdateAdBlock source, destination


sub UpdateAdBlock(source, destination)
	
	' download adblock.ini
	GetHtmlPage source, destination
	
	' show message
	dim s : s = ReadFirstLines(destination, 3)
	MsgBox s, vbInformation, "Adblock updated"

end sub


sub GetHtmlPage (up_http, down_http)

	dim xmlhttp : set xmlhttp = createobject("msxml2.xmlhttp.3.0")
	xmlhttp.open "get", up_http, false
	xmlhttp.send

	dim fso : set fso = createobject ("scripting.filesystemobject")

	dim newfile : set newfile = fso.createtextfile(down_http, true)
	
	'and the text from the XMLHTTP response can then be written to the file:
	newfile.write (xmlhttp.responseText)

	'the file must then be closed:
	newfile.close

	set newfile = nothing
	set xmlhttp = nothing
	set fso = nothing

end sub


function ReadFirstLines(fileName, numberOfLines)
	
	const wChar = "§"
	dim res
	
	' open text file
	dim fso : set fso = createobject ("scripting.filesystemobject")
	dim ts : set ts = fso.OpenTextFile(fileName)
	
	' read the first x lines
	dim x
	for x = 1 to numberOfLines
		res = res & ts.ReadLine & wChar
	next
	
	ts.close
	set ts = Nothing
	set fso = Nothing
	
	' format output string
	if len(res) > 1 then
		res = left(res, len(res) - 1)
		res = replace(res, wChar, vbCrlf)
	end if
	
	ReadFirstLines = res
	
end function
Trovato qui.

01 March 2010

Console Screen Buffer

If you plan on making any console based games with the screen refreshing constantly you will find it flickers a lot unless you use what is known as a buffer. Here I show you a class that has a couple of functions to draw to, and then output the "image" to the console.

public class ScreenBuffer
{					
    //initiate important variables
    public static char[,] screenBufferArray = new char[roomWidth,roomHeight]; //main buffer array
    public static string screenBuffer; //buffer as string (used when drawing)
    public static Char[] arr; //temporary array for drawing string
    public static int i = 0; //keeps track of the place in the array to draw to
 
    //this method takes a string, and a pair of coordinates and writes it to the buffer
    public static void Draw(string text, int x, int y)
    {
        //split text into array
        arr = text.ToCharArray(0,text.Length);
        //iterate through the array, adding values to buffer 
        i = 0;
        foreach (char c in arr)
        {
            screenBufferArray[x + i,y] = c;
            i++;
        }   
    }
 
    public static void DrawScreen()
    {
        screenBuffer = "";
        //iterate through buffer, adding each value to screenBuffer
        for (int iy = 0; iy < roomHeight-1; iy++)
        {
            for (int ix = 0; ix < roomWidth; ix++)
            {
                screenBuffer += screenBufferArray[ix, iy];
            }
        }
    //set cursor position to top left and draw the string
        Console.SetCursorPosition(0, 0);
        Console.Write(screenBuffer);
        screenBufferArray = new char[Game.roomWidth, Game.roomHeight];
    //note that the screen is NOT cleared at any point as this will simply overwrite the existing values on screen. Clearing will cause flickering again.
    }
 
}

roomWidth and roomHeight are the width and height of your console screen respectively. This can easily be set using

Console.SetWindowSize(roomWidth,roomHeight);

Usage

Usage is very simple with this class. First of all you'll need to create the class by using

ScreenBuffer sb = new ScreenBuffer();

This simply create an instance of the ScreenBuffer class with the reference "sb" (you can change this to whatever you want). To draw to it all you need to do is use the method Draw.

ScreenBuffer.Draw("text here",x,y);

Beware that this method will not handle new lines correctly. This could be easily added by using a check within the draw function, and if it detects \n simply jump the the next line in the array. Now all you need to do is call the DrawScreen method at the end of the frame you are displaying and the array will be flushed onto the console screen, giving you a flicker free game!

~ knighty (Graeme Pollard - )

Trovato qui.