Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

№43 рассылки '.Net Собеседник':


Информационный Канал Subscribe.Ru

.Net Собеседник #43

Содержание
  1. От автора
  2. Обзор новостей
  3. Загрузка/скачивание изображений на/с SQL Server
  4. Время кода - Запускаем нити с параметрами на C#
  5. Форумы .Net на www.sql.ru

От автора

Здравствуйте, коллеги!

Число подписчиков рассылки наконец перевалило за, как сейчас говорят, психологически важный рубеж в 3000 .
Также не за горами выпуск третьего номера журнала Алгоритм, это будет последний выпуск полностью выложенный в Сеть. Следующие номера будут выложены в Сеть в урезанном виде.
По-прежнему регулярно обновляется мой блог.
А теперь приятная новость - авторы, статьи которых будут опубликованы в журнале, кроме авторского номера журнала, будут получать гонорар за статью. В зависимости от сложности и объёма статьи гонорар будет колебаться от 10 до 30 долларов США. Авторам, регулярно публикующимся в журнале, со временем ставка будет повышаться.

Так что приглашаю вас опубликовать свою статью в журнале. Требования к статьям здесь.

На этом всё- желаю интересного чтения.

{К содержанию}

Обзор новостей

  1. Вышел Portable.NET 0.7.0
    Portable.NET – набор инструментов, разработанный для построения и запуска веб-сервисов и приложений .NET.
  2. Вышли Genuine Channels v.2.5.0
    GenuineChannels.com объявили о выходе версии 2.5 .NET пакета работы с удалёнными клиентами, находящимися за NAT, файерволлами и прокси-серверами. Используя пакет Genuine Channels, клиенты могут определить, что сервер перестартовал, задействовать расширенные настройки при хостинге, использовать сжатие, шифрование и поддержку SSPI, а также использовать упрощённую разработку событий и многоадресную передачу IP-пакетов.
  3. Вышла экстремально оптимизированная математическая библиотека Extreme Optimization Mathematics Library для .NET v1.1
    Extreme Optimization выпустила версию 1.1 библиотеки Extreme Optimization Mathematics Library для .NET. Новая версия поддерживает кубические сплайны, линейную интерполяцию, модифицированные функции Бесселя и т.п.
  4. Вышел конвертор VB.Net на C# 1.3
    В новой версии 1.3 улучшена аккуратность конвертации, онлайновая помощь, появилась версия для командной строки для пакетных конвертаций. Конвертор от VBConversions VB.Net на C# может конвертировать индивидуальные проекты, фрагменты кода и даже группы проектов в случае необходимости массовой конвертации.
  5. Вышла Dingo 1.1.3
    В Dingo 1.1.3 были устранены несколько ошибок, а также улучшена поддержка xs:group и groupAttribute. В этом выпуске добавлен новый исполняемый файл Jingo, который может генерировать код на Java. Это значит, что Dingo теперь поддерживает C# и Java.
  6. Используйте MSFT Office для разработки и распространения отчётов
    SoftArtisans выпустила 3 версию OfficeWriter .NET приложения для Excel и Word, обладающую улучшенной поддержкой Reporting Services. Пользователи могут создавать и распространять свои отчёты – используя сводные таблицы, VBA, макросы, формулы – не имея на машине Microsoft Office.
  7. Реализуем автоподстройку ширины в таблице
    Автоподстройка ширины – полезная вещь, если вы работаете с таблицами, набор методов и свойств элемента управления TX Text Control содержит всё, что необходимо для реализации такой функциональности. Я закончил полнофункциональный пример, который покажет вам как можно реализовать with автоподстройку ширины с помощью ЭУ TX Text Control.NET.
  8. Импорт данных из листа Excel
    Иногда возникает необходимость слияния данных из различных источников, включая данные из листов Microsoft Excel в один документ. Я предлагаю вам взглянуть на приложение, которое импортирует данные из Microsoft Excel в таблицу TX Text Control.
  9. Вышел Aspose.Word 2.5
    Aspose.Word - компонент для создания отчётов в формате Word, который позволяет вам читать и писать документы Word без использования Microsoft Word.
  10. Разработчикам нравится Spices.NET
    Spices.NET, среда для построения современных графических интерфейсов пользователя для разработчиков на платформе .NET получила престижную награду MSD2D People’s Choice 2005 Award в категории инструменты кодирования, которая считается аналогом Оскара в индустрии.
  11. Вышел ExcelLite 1.4
    Легко создавать, конвертировать, читать и писать файлы в формате Microsoft Excel (как XLS, так и CSV), используя этот, на 100% управляемый, компонент.

{К содержанию}

Статья номера

Загрузка/скачивание изображений на/с SQL Server

ЯЗЫК: C#
Автор статьи: Alexandru Ghiondea

ПЕРЕВОД: Чужа В.Ф. ака hDrummer
КОД К СТАТЬЕ: Демо проект 19КБ, Скрипт к БД 1КБ

Вступление

Для того, чтобы снабдить ваше приложение классными картинками, вы можете использовать как минимум два способа. Один из них – можно сохранять картинки в папку, а затем записывать пути к ним в базу данных (БД). Другой – записывать весь файл, вместе с именем, в БД. У каждого способа есть свои плюсы и минусы:

  1. Можно случайно удалить файл, если он будет храниться в папке. Если такое происходит, то в БД или вашем конфигурационном файле будет храниться неправильная ссылка. Однако, пространство на жестком диске дешевеет и вы можете хранить на диске много файлов.
  2. Если же хранить файлы в БД, то можно использовать настройки безопасности, используемые в ней. Также не будет неправильных ссылок. Однако, нужно помнить о том, что пространство в хранилищах БД намного более дорого.
Другая идея – сохранять уменьшенную копию изображения в БД – для быстрого доступа, а само изображение хранить на диске. Конечно, у каждого приложения есть свои требования, а вам нужно выбрать какой способ наилучшим образом будет им соответствовать. OK. Хватит философии! Давайте погрузимся в более интересные вещи.

Приложение

Задача загрузки файла в БД достаточно проста. При создании таблицы на сервере необходимо использовать определенный тип данных. Этот тип должен уметь хранить большие объёмы двоичных данных. При использовании Microsoft SQL Server этот тип данных называется image. Чтобы узнать больше, см. BLOB (Binary Large OBject) – там есть определение, а в Books Online есть подробное описание. Клиент должен получить данные из файла в двоичном формате – в виде массива байт – и вызвать процедуру на сервере с параметром-массивом.

Процедуры SQL Server’a

Здесь будем считать, что у нас есть БД Pictures на сервере, в которой есть таблица Pictures. Структура этой таблицы такова:

Имя поля Тип поля
kFileName Long
Picture Image
FileName Varchar(250)

У меня также есть хранимые процедуры (ХП) для загрузки, скачивания и лов. Они приведены ниже.

Для закачки файла UploadFile:
CREATE PROCEDURE [dbo].[UploadFile]
(
@Picture image,
@FileName varchar(250),
@kFileName bigint output
)
AS
insert into Pictures(Picture, FileName) values (@Picture,@FileName)
select @kFileName = SCOPE_IDENTITY()
GO

Для скачивания файла DownloadFile:
CREATE PROCEDURE [dbo].[DownloadFile]
(
@kFileName bigint,
@FileName varchar(250) output
)
AS

select Picture, FileName
from Pictures
where kFileName=@kFileName
GO

Для получения списка закачанных файлов getUploadedFiles:
CREATE PROCEDURE [dbo].[getUploadedFiles]AS
Select ltrim(str(kFileName)) + " - " + FileName as Name
from Pictures
GO

Класс на C# - с комментариями

using System;
using System.IO;
using System.Data;
using System.Text;
using System.Data.SqlClient;

//Autor: Ghiondea Alexandru
//Date: 08 october 2004
// Описание: Содержит методы для закачки и скачки файлов
// с MS SQL Server
//
namespace PicturesInSQLServer
{
///
/// Этот класс управляет закачкой и скачкой файлов
///

public class TransferPictures
{
///
/// Получаем список закачанных файлов в dataSet
///

///
///
public void GetUploadedFiles(ref DataSet ds, string table)
{
//
// Переменные для соединения с сервером.
//
SqlConnection conn =null;
SqlCommand cmd = null;
SqlDataAdapter da = null;
// ----------------------------------------------

try
{
//
// Если таблица уже существует, то очищаем её, иначе – //добавляем новую.
//
if (ds.Tables.Contains(table))
ds.Tables[table].Clear();
else
ds.Tables.Add(table);
// ----------------------------------------------


//
// Создаём соединение к БД и инициализируем команду
//
conn = new SqlConnection(ConnectionString());
cmd = new SqlCommand("getUploadedFiles",conn);
cmd.CommandType = CommandType.StoredProcedure;
// ----------------------------------------------

da = new SqlDataAdapter(cmd);
//
// Открываем соединение и заполняем dataset
//
conn.Open();
da.Fill(ds,table);
conn.Close();
// ----------------------------------------------
}
catch(Exception e)
{
//
// Если происходит ошибка, то мы присваиваем null результату
// и отображаем ошибку пользователю
// с информацией о StackTrace для целей отладки.
//
Console.WriteLine(e.Message + " - " + e.StackTrace);
}
}

///
/// Загружаем файл на сервер.
///
/// id файла на сервере.
public long UploadFile(string FileName)
{
if (!File.Exists(FileName))
{
return -1;
}

FileStream fs=null;
try
{
#region Reading file

fs = new FileStream(FileName,FileMode.Open);

//
// Размер закачиваемого файла
//
FileInfo fi = new FileInfo(FileName);
long temp = fi.Length;
int lung = Convert.ToInt32(temp);
// ------------------------------------------

//
// Считываем содержимое файла в массив байт.
//
byte[] picture=new byte[lung];
fs.Read(picture,0,lung);
fs.Close();
// ------------------------------------------
#endregion
long result = uploadFileToDatabase(picture,fi.Name);

return result;
}
catch(Exception e)
{
Console.WriteLine(e.Message + " - " + e.StackTrace);
return -1;
}
}

///
/// Обёртка для скачки файла из БД.
///

///
///
/// Массив байт ИЛИ null если ID не найден
public byte[] DownloadFile(long kFileName, ref string fileName)
{
byte[] result =downloadFileFromDatabase(kFileName, ref fileName);
return result;
}

///
/// Возвращает строку соединения для соединения с БД
///

/// Строка соединения
public static string ConnectionString()
{
//
// Считаем, что БД на той же машине, где запущена программа
// Для подсоединения к удаленному серверу впишите в
// 'Data Source' имя этого сервера
return "Connect Timeout=600;Integrated Security=SSPI;" +
"Persist Security Info=False;Initial Catalog=Pictures;" +
"Packet Size=4096;Data Source=" +
System.Environment.MachineName.Trim();
}

///
/// Загрузка файла на SQL Server.
///

///
///
/// Уникальный ID файла на сервере ИЛИ -1
/// при возникновении ошибки.
private long uploadFileToDatabase(byte[] picture, string fileName)
{
SqlConnection conn = null;
SqlCommand cmd =null;
SqlParameter kFileName =null;
SqlParameter FileName =null;
SqlParameter pic =null;
// По умолчанию мы считаем, что произошла ошибка. Иначе //меняем значение на уникальное id файла
long result=-1;

try
{
//
// Соединяемся с БД.
//
conn = new SqlConnection(ConnectionString());
cmd = new SqlCommand("UploadFile",conn);
// Предполагаем, что есть ХП с именем UploadFile
cmd.CommandType = System.Data.CommandType.StoredProcedure;
// ----------------------------------------------
// Инициализируем параметры и присваиваем значения
// перед отсылкой их на сервер
//
kFileName = new SqlParameter("@kFileName",
System.Data.SqlDbType.BigInt,8);
kFileName.Direction = ParameterDirection.Output;
// Этот параметр не имеет размера, поскольку
// мы его не знаем.
pic = new SqlParameter("@picture",SqlDbType.Image);
pic.Value = picture;

FileName = new SqlParameter("@FileName",SqlDbType.VarChar,250);
FileName.Value = fileName;
// ----------------------------------------------
// Добавляем параметры.
// Помните, что порядок добавления
// ОЧЕНЬ важен!
cmd.Parameters.Add(pic);
cmd.Parameters.Add(FileName);
cmd.Parameters.Add(kFileName);
// ----------------------------------------------
// Oткрываем соединение и выполняем команды.
//
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
// ----------------------------------------------
// В результате получаем уникальный идентификатор созданный ///в БД.
//
result = (long)kFileName.Value;
// ----------------------------------------------
// Убираем объекты из памяти.
//
conn.Dispose();
cmd.Dispose();
// ----------------------------------------------
}
catch(Exception e)
{
Console.WriteLine(e.Message + " - " + e.StackTrace);
result = -1;
// ----------------------------------------------
}

return result;
}
///
/// Скачиваем файл из БД
// согласно уникальному id в БД.
///

///
///
/// Массив байт, содержащий информацию
private byte[] downloadFileFromDatabase(long kFile, ref string FileName)
{
SqlConnection conn =null;
SqlCommand cmd = null;
SqlParameter kFileName = null;
SqlParameter fileName = null;
SqlDataReader dr=null;
byte[] result=null;

try
{
conn = new SqlConnection(ConnectionString());
cmd = new SqlCommand("DownloadFile",conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
// ----------------------------------------------
// Инициализируем параметры для отсылки на сервер
//
kFileName= new SqlParameter("@kFileName",System.Data.SqlDbType.BigInt,8);
kFileName.Value = kFile;
fileName = new SqlParameter("@FileName",SqlDbType.VarChar,250);
fileName.Direction = ParameterDirection.Output;
// ----------------------------------------------
// Добавляем параметры к БД.
// Помните, что порядок добавления очень важен!
cmd.Parameters.Add(kFileName);
cmd.Parameters.Add(fileName);
// ----------------------------------------------
// Используем dataReader для считывания одной записи и //возвращения значения в виде поля image
conn.Open();
dr = cmd.ExecuteReader();
dr.Read();
//
// Приводим значение
// к типу byte[]
//
result = (byte[])dr.GetValue(0);
//
// Также возвращаем значение имени файла, ассоциированное с //массивом байт.
FileName = (string)dr.GetValue(1);
//
// Закрываем datareader и соединение
//
dr.Close();
conn.Close();
//
// И снова зачем-то вызываем методы Dispose ;)
//
conn.Dispose();
cmd.Dispose();
// ------------------------------------------
}
catch(Exception e)
{
Console.WriteLine(e.Message + " - " + e.StackTrace);
result = null;
}
return result;
}
}
}

Простое приложение

Я также написал небольшое приложение для демонстрации использования этих методов. Приложение загружает файл на сервер и отображает список файл на сервере. щёлкнув два раза на имени файла в списке, мы производим скачивание файла и отображаем его в специальном окне. Ниже – некоторые интересные фрагменты кода:

private void UploadedFiles_DoubleClick(object sender, System.EventArgs e)
{
// Ищем уникальный id файла.

DataRowView drv = (DataRowView) UploadedFiles.SelectedItem;
string selectedText = drv.Row["Name"].ToString();
long id=-1;
id = long.Parse(selectedText.Substring(0,selectedText.IndexOf(" - ",0)).Trim());

string filename=null;
TransferPictures up = new TransferPictures();
byte[] result = up.DownloadFile(id,ref filename);
up = null;
try
{
//
// Мы не можем напрямую присвоить массив байт image.
// Мы используем MemoryStream, объект, который создаёт файл //в памяти
// a потом мы передаём его для отображения
//
MemoryStream ms= new MemoryStream(result,0,result.Length);
Image im = Image.FromStream(ms);
Picture.Image = im;
}
catch(Exception ee)
{
MessageBox.Show("Произошла ошибка.\n" + ee.Message);
}
}
private void UploadFile_Click(object sender, System.EventArgs e)
{
//
// Получаем файл для загрузки на сервер
//
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog();
if (ofd.FileName=="" || !File.Exists(ofd.FileName))
{
//
// Если с запрошенным файлом не всё в порядке
//
return;
}

TransferPictures up = new TransferPictures();
long id =up.UploadFile(ofd.FileName);
string msg=null;
if (id >0)
{
msg = "Загрузка успешна";
LoadInformationFromDataBase();
}
else
{
msg = "Произошла ошибка";
}
MessageBox.Show(msg);
}

private void LoadInformationFromDataBase()
{
TransferPictures up = new TransferPictures();
up.GetUploadedFiles(ref ds,"Pictures");

UploadedFiles.DataSource = ds.Tables["Pictures"];
UploadedFiles.DisplayMember = "Name";
}

private void frmMain_Load(object sender, System.EventArgs e)
{
LoadInformationFromDataBase();
}

Выводы

Итак, выбор техники хранения файла за вами. Я попробовал показать вам, как хранить их в БД. Удачного кодирования!

{К содержанию}

Время кода

Запускаем нити с параметрами на C#

ЯЗЫК: C#
Автор статьи: ?

ПЕРЕВОД: Чужа В.Ф. ака hDrummer


Вступление

В новостных группах по языку C# многие люди спрашивают, каким образом можно передать параметры в новую нить. Другими словами, если новая нить нуждается в специфической информации для запуска (как это обычно бывает), как поместить такую информацию в эту нить? Делегат ThreadStart не принимает параметров. Т.е. информацию нужно сохранить где-то еще. Обычно это приводит к созданию нового объекта класса и использованию его для хранения этой информации. Например, нам нужна программа, которая будет получать и обрабатывать содержимое нескольких URL, причём должна она делать это в фоновом режиме. Для этого можно написать такой код:

public class UrlFetcher
{
private string url

public UrlFetcher (string url)
{
this.url = url;
}

public void Fetch()
{
// здесь используем url
}
}

//[... в другом классе ...]

UrlFetcher fetcher = new UrlFetcher (myUrl);
new Thread (new ThreadStart (fetcher.Fetch)).Start();

Иногда вам необходимо просто вызвать метод в некотором классе (возможно в том, который сейчас выполняется) со специфичным параметром. В этом случае, вы можете использовать вложенный класс, чьё предназначение – всего лишь выполнить этот вызов, состояние хранится в этом же классе, а делегат, стартовавший нить, всего лишь вызывает «настоящий» метод с соответствующим параметром.

Используем ThreadPool

При запуске новой нити вы всегда должны помнить о том, что, возможно, более выгодно будет использовать ThreadPool, который обработает нити для вас и поместит их в очередь, если пул полон. ThreadPool – прекрасный выбор для тех задач, которые часто выполняются и занимают мало времени – просто потому, что не приходится пересоздавать и уничтожать нити.

Для того чтобы добавить задание в пул, нужно вызвать ThreadPool.QueueUserWorkItem с делегатом WaitCallback. Одно из преимуществ использования WaitCallback в том, что можно указать «состояние» при помещении сущности в очередь и это состояние представляется делегату как параметр метода. Однако этот параметр не является сильнотипизированным – его типом является всего лишь object – и я буду иметь более строготипизированный метод, который вызовется делегатом WaitCallback и который должен быть использован где-то в коде. Например, вы можете написать два метода обработки URL:

// этот метод можно использовать в коде где угодно
public void Fetch (string url)
{
this.url = url;
}

// этот метод можно использовать в качестве делегата для WaitCallback для помещения в очередь пула
private void Fetch(object url)
{
Fetch ((string) url);
}

// а вызывается он так:
ThreadPool.QueueUserWorkItem (new WaitCallback (Fetch), myUrl);

Асинхронный вызов делегата

Альтернативой (которая тоже неявно использует пул нитей) является асинхронный вызов делегата. У него есть преимущество в том, что можно передать больше одного параметра в метод делегата, а также в том, что их можно проверить на соответствие типов во время компиляции. Это возможно благодаря компилятору C#, добавляющего пару методов к типу делегата: BeginInvoke и EndInvoke. Метод BeginInvoke всегда принимает те параметры, которые принимает делегат, вместе с параметром AsyncCallback и параметром типа object в качестве состояния. Он возвращает ссылку IAsyncResult. При вызове BeginInvoke, сущность помещается в рабочую очередь пула нитей и в то время как она выполняется, вызывается делегат со специфическими параметрами. Когда делегат завершает работу, вызывается параметр делегата AsyncCallback, возвращающий ссылку на IAsyncResult. Ссылка может быть использована для нахождения оригинального параметра состояния, самого делегата, значения, возвращенного после операции через делегат и т.п. Заметьте, что для отыскания оригинального делегата вам нужно привести ссылку типа IAsyncResult к AsyncResult. Я не уверен почему именно так спроектирован каркас .Net, но если вы не хотите использовать приведение типов, тогда можно использовать делегат как свой собственный параметр состояния. Метод EndInvoke берёт только IAsyncResult, и возвращает тот же тип, что и сам делегат. Вот и полный пример:

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

class AsyncTest
{
delegate string UrlFetcher(string url);

public static void Main()
{
UrlFetcher u = new UrlFetcher (Fetch);
u.BeginInvoke ("some url", new AsyncCallback (AfterFetch), "this is state");
// Просто покажем что происходит при
// вызове fetch
for (int i= 0;i < 10; i++)
{
Console.WriteLine ("Счётчик нитей: {0}", i);
Thread.Sleep(1000);
}
}

static string Fetch (string url)
{
// Симулируем задержку
Thread.Sleep (5000);
return "Содержимое url";
}

static void AfterFetch (IAsyncResult result)
{
Console.WriteLine ("Делегат отработал.");
Console.WriteLine (" Состояние: {0}", result.AsyncState);
AsyncResult async = (AsyncResult) result;
UrlFetcher fetcher = (UrlFetcher) async.AsyncDelegate;
Console.WriteLine (" Содержимое: {0}", fetcher.EndInvoke(result));
}
}

Вот вывод на экран вышеприведенного кода:

Счётчик нитей: 0
Счётчик нитей: 1
Счётчик нитей: 2
Счётчик нитей: 3
Счётчик нитей: 4
Делегат отработал.
Состояние: this is state
Содержимое: Coдержимое url
Счётчик нитей: 5
Счётчик нитей: 6
Счётчик нитей: 7
Счётчик нитей: 8
Счётчик нитей: 9

Смотрите MSDN по операциям BeginRead и EndRead класса System.IO.Stream - там много примеров того, как работают асинхронные вызовы.

Запомните: Вы должны всегда вызывать EndInvoke для делегатов, которые исполняются асинхронно, даже если вам ни к чему результат операции – иначе вы можете спровоцировать утечку памяти. К счастью, есть пути упрощения таких операций, так как показано в Advanced-DotNet mailing list archives

Решения будущего: анонимные методы

Анонимные методы – одно из будущих улучшений C#. Они помогут вам специфицировать блоки кода как методы внутри других методов и использовать эти методы как делегаты. Вы можете получить доступ к переменным (включая локальные переменные и параметры «внешнего» метода) внутри анонимного метода. Например, использование анонимного метода для обработки URL с использованием нормального делегата ThreadStart:

ThreadStart starter = new ThreadStart()
{
Fetch (myUrl);
};
new Thread(starter).Start();

Всё это можно выполнить за один шаг, создав сразу нить и делегат одной строкой кода, но я думаю что вышеприведенный код более читаем. Вот похожий код использующий WaitCallback и помещающий задание в очередь пула ThreadPool:

WaitCallback callback = new WaitCallback (state)
{
Fetch ((string)state);
};
ThreadPool.QueueUserWorkItem (callback, myUrl);

Заметьте, как выполнено объявление. Подход, конечно, может измениться в финальной реализации. Больше узнать об анонимных методах можно на странице Microsoft C# - будущие особенности языка.


{К содержанию}

Форумы .Net - вопросы оставшиеся без ответа

Donwload Visual Studio
Поиск
Прога говорит что у InteropServices закончилась лицензия
Массив в хранимую процедуру Oracle
varbinary
Почему не подключается ado.net
Display related data (many-to-many)
OWC PivotTable


На этом сорок третий выпуск .Net Собеседника закончен.
До следующего номера.


Чужа Виталий Ф. aka hDrummer, MCAD, MCDBA, MCP
hdrummer ухо gmail точка ru - жду ваши предложения и замечания.



Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.dotnetgrains
Отписаться
Вспомнить пароль

В избранное