tag:blogger.com,1999:blog-24316680999492607192024-03-18T12:48:13.754+03:00.NetBlog - блог о программировании на C# .Net, и других, не мене интересных вещах.Заметки о разработке ПО, советы по .net, SharePoint, SQL, архитектура приложений, литература по программированию. А также просто просто мысли о жизни и рассказы о том, что интересно автору, например путешествиях и вкусной еде ;)Unknownnoreply@blogger.comBlogger82125tag:blogger.com,1999:blog-2431668099949260719.post-10889123524086981012015-09-30T15:51:00.001+03:002015-09-30T15:51:38.908+03:00Про using или знаете ли вы что...Наверняка, вы знаете что в C# есть такая конструкция, как using. И, скорее всего, в курсе, что использовать его можно и нужно только с объектами, реализующими интерфейс IDisposable (и, соответственно, скорее всего, что-то делающими с неуправляемыми ресурсами). На всякий случай, напомню, что конструкция вида:<br>
<pre class="brush:csharp">
using (someType obj = new someType())
{
//тут что-то происходит
}
</pre>
разворачивается компилятором вот в такую:<br>
<br>
<pre class="brush:csharp">
someType obj = new someType();
try
{
//тут что-то происходит
}
finally
{
//если объект значимого типа (value-type)
((IDisposable)obj).Dispose();
//или, если объект ссылочного типа (reference-type)
if (obj!=null)
((IDisposable)obj).Dispose();
}
</pre>
а где же блок catch, спросите вы? Почему его нет? И почему не предусмотрен вариант using, где его можно задать?
<br>
<a href="http://www.dotnetblog.ru/2015/09/using.html#more">Дальше »</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2431668099949260719.post-46793909183156677652015-03-25T20:47:00.002+03:002015-03-25T20:48:01.789+03:00Как в .Net получить действительно случайные числаНаверняка, всем известно о существовании в .Net класса System.Random, позволяющего получать якобы случайные числа практически без особых как умственных, так и временных затрат. Представьте что у нас есть такой вот метод, который чисто ради эксперимента мы вызовем в цикле несколько раз:<br>
<pre class="brush:csharp">
static string GetRandomNum(int minValue, int maxValue)
{
Random rnd = new Random();
return rnd.Next(minValue, maxValue).ToString();
}
for (int i = 0; i < 10; i++)
{
Console.WriteLine(GetRandomNum(1,11));
}
</pre>
<br>
<br>
В данном случае вы получите совершенно одинаковые все "случайные" цифры.<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-FmL7smayibg/VRLlYt2J19I/AAAAAAAAgMA/ZyO-GnXvuBg/s1600/rnd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-FmL7smayibg/VRLlYt2J19I/AAAAAAAAgMA/ZyO-GnXvuBg/s1600/rnd.jpg" height="166" width="640"></a></div>
<br>
Происходит так потому, что при инициализации объекта Random с использованием конструктора по умолчанию в качестве числа, использующегося для вычисления случайных чисел используется Environment.TickCount (количество миллисекунд, прошедших со времени старта системы), который обновляется раз в 15.6 миллисекунд. <br>
<a href="http://www.dotnetblog.ru/2015/03/net.html#more">Дальше »</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2431668099949260719.post-1506655533761277502015-03-12T13:26:00.001+03:002015-03-12T13:26:56.899+03:00Используем сессию в обработчиках (HTTP handlers) ASP.NETПредставьте себе гипотетическую ситуацию, когда вам нужно отдавать пользователю файлы, с, допустим, какими-то индивидуальными для каждого пользователя данными, причем именно отдавать уже готовые файлы, а не генерировать на лету. Самым простым и очевидным вариантом было бы создать обработчик, который будет вызываться для запросов вида "*_report.pdf", но для этого нам нужно понимать, можно ли отдавать пользователю файл, который он запрашивает или он принадлежит другому пользователю.<br>
Передавать идентификатор в явном виде не только не правильно идеологически, но и просто не красиво, да и сохраненный файл, полученный по ссылке вида <b>10102_u323467_report.pdf?sessId=05446DA8F736B29A</b> будет по умолчанию сохранен с таким же "кривым" именем.<br>
<br>
Значительно проще положить этот идентификатор в сессию и получать его в обработчике уже оттуда. Для того, чтобы объект Session был доступен, нам нужно, чтобы обработчик наследовал не только от интерфейса IHttpHandler, но од одного из интерфейсов IRequiresSessionState или IReadOnlySessionState в зависимости от того нужен ли нам доступ только на чтение (IReadOnlySessionState) или на чтение и запись (IRequiresSessionState). На самом деле, записать в объект сессии вы сможете что угодно в любом случае, единственное отличие, что при использовании IReadOnlySessionState в конце обработки запроса данные сессии не сохраняются.<br>
<br>
<a href="http://www.dotnetblog.ru/2015/03/http-handlers-aspnet.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-70123473460687359112015-03-11T17:27:00.003+03:002015-03-11T19:10:23.198+03:00Как сделать поля ввода с "подсказками" с помощью jQuery и CSSИногда мало сделать просто красивый дизайн странички, а хочется еще дать пользователю какие-то подсказки по заполнению полей. Самый простой и наиболее очевидный способ - создать поля с подсказками в виде "текста по умолчанию", примерно вот такие:<br>
<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-jqlImzdXOV4/VQBHfqCER0I/AAAAAAAAf8o/n1H9rMTBaT0/s1600/mocjup.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-jqlImzdXOV4/VQBHfqCER0I/AAAAAAAAf8o/n1H9rMTBaT0/s1600/mocjup.jpg" height="66" width="400"></a></div>
<br>
В принципе, все современные браузеры, поддерживают стандарт HTML5 и, соответственно, атрибут <b>placeholder</b>, которой для этой цели и был придуман. Проблема в том, если вам необходима поддержка старых браузеры или чуть менее старые версии Internet Explorer (который начал поддерживать этот атрибут только в 10 версии), то подсказку созданную с помощью него они не увидят.<br>
Если вы используете на своем сайте jQuery, то есть простое и быстрое решение для создания таких полей буквально несколькими строчками кода. Прежде всего нужно создать стиль отображения "подсказок":<br>
<br>
<pre class="brush:css"><style type="text/css">
.helpField { background:white; }
.blankHelpFieldText { color: #a1a1a1; font-style: italic; }
</style>
</pre>
<br>
<br>
При этом, первый стиль несет в себе единственное практическое предназначение - быть "свойством" к которому будет привязываться скрипт отображения текста подсказки. Так что, вместо background можете написать что вам больше подходит, например width.<br>
<br>
<a href="http://www.dotnetblog.ru/2015/03/jquey-css.html#more">Дальше »</a>Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2431668099949260719.post-65223245596156358142015-02-05T13:54:00.000+03:002015-02-05T13:54:53.815+03:00Как победить ошибку "The SDDL string contains an invalid sid..." при установке SharePoint 2013Я уже два раза при установке SharePoint Server 2013 сталкивался c возникновение странной ошибки "The SDDL string contains an invalid sid or a sid that cannot be translated" или "Строка SDDL содержит недопустимый sid либо sid, который не может быть преобразован." для русскоязычной версии. Выглядит момент появления ошибки вот так:<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-4iR_4UHORIQ/VNNJryeLXuI/AAAAAAAAefM/8dOMSbUwF9o/s1600/sharepoint_error.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-4iR_4UHORIQ/VNNJryeLXuI/AAAAAAAAefM/8dOMSbUwF9o/s1600/sharepoint_error.jpg" height="448" width="640"></a></div>
<div>
<br></div>
<div>
Как это часто периодически бывает с продуктами Microsoft текст ошибки никак не намекает ни то что на решение проблемы, но даже на то в какую сторону надо смотреть. </div><a href="http://www.dotnetblog.ru/2015/02/sddl-string-contains-invalid-sid.html#more">Дальше »</a>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2431668099949260719.post-73283164088474986142015-01-11T12:08:00.000+03:002015-02-03T08:01:02.969+03:00Делаем локализацию сайта на ASP.NET MVCПредставьте, что вы решили делать сайт с использованием ASP.NET MVC. И, помимо всего прочего, вам на этом сайте вам нужна возможность отображения его на нескольких языках. Задача, хоть и кажущаяся с первого взгляда не самой тривиальной, на самом деле, достаточно проста. И я сейчас расскажу что для этого нужно сделать.<br>
<div>
<br></div>
<div>
Во-первых, необходимо как-то передавать идентификатор языка. Можно, конечно, придумать какое-нибудь извращение, типа хранения текущего языка в сессии, но лучше всего просто передавать его в URL. Как минимум, в это случае, локализованными ссылками на ваш сайт можно будет без проблем делиться, хоть в соцсеятх, хоть пересылать их по e-mail. </div>
<div>
Для этого в вашем проекте открываем файл <b>RouteConfig.cs</b>, находящийся в папке <b>App_Start</b> и добавляем туда путь для локализованного контента.</div>
<div>
<pre class="brush:csharp"> public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Localization",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { lang = "ru", controller = "Home", action = "Index", id = UrlParameter.Optional },
//ограничение необходимо, чтобы отличить параметр языка от параметра контроллера.
//В данном случае, в качестве параметра lang подходят все двухсимвольные комбинации из букв латинского алфавита, например "en" или "fr"
constraints: new { lang = @"[a-z]{2}" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
</pre>
</div>
<div>
<br></div>
<div>
Теперь, если в URL содержится идентификатор языка, то он будет приходить нам в коллекции RequestContext.RouteData, и получить его проще всего в методе в методе Initialize контроллера. Давайте для простоты сделаем локализованную страничку авторизации, которая будет отображаться сразу же при входе на сайт, то есть по пути /.<br>
<br>
</div><a href="http://www.dotnetblog.ru/2015/01/aspnet-mvc.html#more">Дальше »</a>Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2431668099949260719.post-75230816666771392572014-12-15T13:06:00.001+03:002014-12-15T13:13:16.498+03:00О передаче параметров в C#Давайте сразу начнем с кода. У нас есть вот такой код, давайте разберемся почему он выводит то, что выводит:<br>
<br>
<pre class="brush:csharp">
class Program
{
static void Main(string[] args)
{
int a = 1;
ProcessValue(a);
Console.WriteLine(a.ToString());
//здесь будет выведено 1
TestClass test = new TestClass();
test.val = 2;
ProcessRef(test);
Console.WriteLine(test.val.ToString());
//здесь будет выведено 10
TestClass test = new TestClass();
test.val = 3;
Process(test);
Console.WriteLine(test.val.ToString());
//а здесь будет выведено 3
}
static void ProcessValue(int par)
{
par = 3;
}
static void ProcessRef(TestClass par)
{
par.val = 10;
}
static void Process(TestClass par)
{
par = new TestClass();
par.val = 100;
}
}
public class TestClass
{
public int val;
}
</pre>
<br>
Вы, наверняка, знаете, что в .Net есть значимые (value) и ссылочные (reference) типы. Первые - размещаются полностью в стеке, а вторые размещаются в управляемой куче, а в стеке размещается только указатель на них.<br>
<br>
<a href="http://www.dotnetblog.ru/2014/12/c.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-12579871076694649832014-12-07T10:17:00.000+03:002014-12-07T10:24:30.553+03:00Обработка исключений при работе с WCF-сервисамиНаверняка вы сталкивались с ситуацией, когда в случае ошибки в WCF-сервисе нужно передать клиенту какие-либо данные либо, например, подробное описание что случилось. Очень часто встречаются реализации WCF- сервисов, использующие возвращаемые клиенту объекты с дополнительными, используемыми только в случае ошибки, полями, даже если реализация метода не требует возврата какого-либо результата клиенту. Так делают потому, что если просто выбросить исключение, то клиент не получит практически никакой информации о том, что случилось. Представьте, что у нас есть WCF сервис вот с таким простым контрактом и реализацией.<br>
<div>
<br></div>
<pre class="brush:csharp">
//контракт
[ServiceContract]
public interface IDataService
{
[OperationContract]
void TestError();
}
//реализация
public void TestError()
{
throw new Exception("Error!");
}
</pre>
<br>
<div>
В если реализовать сервис именно так, то на клиент придет исключение, которое не дает никаких сведений о случившемся:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-Iz0_wINPjh0/VIP0zIvAXMI/AAAAAAAAdNM/OvDY08anqGk/s1600/error_message.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-Iz0_wINPjh0/VIP0zIvAXMI/AAAAAAAAdNM/OvDY08anqGk/s1600/error_message.jpg" height="120" width="640"></a></div>
<div>
<br>
Можно, конечно, как написано в ошибке, включить IncludeExceptionDetailInFaults, как написано в сообщении об ошибке. Но это свойство не рекомендуется использовать кроме как для отладки, так как при этом любой клиент в случае ошибки получить все данные о стеке вызовов и структуре вашего сервиса, что очень нехорошо с точки зрения безопасности.<br>
Но, помимо варианта для отладки и архитектурно не самого лучшего варианта с дополнительным полем в результате вызова, есть и третий вариант - более удобный и более правильный.<br>
<br>
</div><a href="http://www.dotnetblog.ru/2014/12/wcf.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-44164657408868135192014-12-06T10:06:00.005+03:002015-01-19T22:50:20.401+03:00Несколько мыслей о получении IP адреса клиента в ASP.NETПолучение IP-адреса клиента - это, наверное, один из самых интересных и неоднозначных вопросов не только в ASP.NET, но и вообще в веб-разработке. Вариантов, как это сделать несколько, и у каждого из способов есть как сторонники, так и противники. Попробую рассказать вам об этих вариантах, чем они отличаются друг от друга и что лучше использовать.<br>
<br>
Итак, самый широко известный в мире ASP.NET способ получения IP-адреса клиента - это использование <b>HttpContext.Current.Request.UserHostAddress</b>, который, по сути является оберткой над HTTP заголовком REMOTE_ADDR, в которую записывается адрес хоста от которого серверу пришел запрос. А этот заголовок используется практически во всех языках программирования, для целей определения IP клиента. И везде не утихают споры правильно ли использовать именно его. Почему? Потому, что REMOTE_ADDR содержит адрес компьютера, установившего соединение с сервером. Во времена становления интернет и появления протокола HTTP этик компьютером почти наверняка являлся клиент, так что все было хорошо. Сейчас же, в большинстве случаев, в REMOTE_ADDR будет адрес прокси сервера внутренней сети (корпоративной, или домашней - смысла это не меняет) через который прошел запрос клиента.<br>
И еще один пример, с которым, особенно часто сталкиваются Linux программисты, в результате криво настроенного nginx. ;)<br>
Представьте себе ситуацию, что у вас есть криво настроенный балансировщик нагрузки. В таком случае в REMOTE_ADDR будет 10.10.0.2, что, естественно совершенно не клиентский адрес.<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-ImnPx_t9upo/VIKk3aqbzfI/AAAAAAAAdMU/vJN3LS3n4t8/s1600/server.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-ImnPx_t9upo/VIKk3aqbzfI/AAAAAAAAdMU/vJN3LS3n4t8/s1600/server.jpg" height="160" width="400"></a></div>
<br>
<a href="http://www.dotnetblog.ru/2014/12/ip-aspnet.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-7829920052650600032014-11-27T13:37:00.006+03:002014-11-27T13:46:07.312+03:00Как получить IP-адрес клиента в WCF-сервисе.Если вам нужно узнать с какого адреса приходит обращение к вашему WCF-сервису, то сделать это вы можете несколькими способами в зависимости от версии .Net Framework. Давайте по порядку.<br>
В версии 3.0 (то есть, самая первая версия .Net, в которой стала доступна WCF) по заверениям Microsoft не существует гарантированного способа это сделать. В принципе, если сервис хостится на IIS, то можно попробовать пару извращений, типа получения IP-адреса клиента из логов сервера (хотя встает вопрос как определять какая из записей лога соответствует текущему запросу). В общем, предлагаю придерживаться позиции Microsoft по этому вопросу ;)<br>
В версии .Net 3.5 в WCF появляется класс <b>System.ServiceModel.OperationContext</b>, так что подключаем сборку System.ServiceModel и используем вот такой код, который и вернет на IP клиента:<br>
<a href="http://www.dotnetblog.ru/2014/11/ip-wcf.html#more">Дальше »</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2431668099949260719.post-57287956067779103062014-11-23T21:26:00.002+03:002014-11-23T21:26:34.519+03:00Отладка 64-битных веб-приложений в Visual StudioПредставьте себе ситуацию, то вы разрабатываете веб-приложение, которое либо просто само по себе 64-битное (x64), либо еще и использует какие-либо x64 библиотеки. При попытке запуска отладки такого приложения вы получите сообщение об ошибке из серии BadImageFormatException.<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-S7kZh9ZtJtU/VHIiTZ18ZXI/AAAAAAAAdAk/h51B6uNVdUU/s1600/web_error.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-S7kZh9ZtJtU/VHIiTZ18ZXI/AAAAAAAAdAk/h51B6uNVdUU/s1600/web_error.jpg" height="84" width="640"></a></div>
<br>
А происходит такое по тому, что IIS Express, используемый в Visual Studio для отладки, работает как 32-битный процесс, в чем легко убедится, взглянув в Task Manager:<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-uHv9Tlhcv98/VHIj8_1uEzI/AAAAAAAAdAs/v2OeTS4in2U/s1600/32bit_iis.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-uHv9Tlhcv98/VHIj8_1uEzI/AAAAAAAAdAs/v2OeTS4in2U/s1600/32bit_iis.jpg" height="170" width="640"></a></div>
<br>
И если при использовании версии Vsual Studio до 2012 единственным способом было использование для отладки локального "большого" IIS, соответствующим образом настроив свойства проекта:<br>
<br>
<a href="http://www.dotnetblog.ru/2014/11/64-visual-studio.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-14040711795071861512014-11-22T11:29:00.001+03:002014-11-22T11:29:05.646+03:00Ошибки 0x800F081F и 0x800F0906 при установке .Net Framework 3.5 на Windows 8/8.1По умолчанию .Net Framework 3.5 в Windows 8 и 8.1 не устанавливается, так что, во-первых, он не будет доступен в Visual Studio, а во-вторых, при попытке запустить что-то, что использует .Net 3.5 (например Windows 7 SDK) вы увидите примерно такое предложение:<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-RmlCpKrg80c/VHA-h_h9hQI/AAAAAAAAc-U/hKCPsOeoLeU/s1600/IC606071.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-RmlCpKrg80c/VHA-h_h9hQI/AAAAAAAAc-U/hKCPsOeoLeU/s1600/IC606071.png" height="266" width="400"></a></div>
<br>
Не проблема, наверняка подумаете вы, и нажмете "Установить". В большинстве случае это, к сожалению, ни к чему хорошему не приведет и вы получите ошибку<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/--GqJBqRYyWI/VHBBGO45sTI/AAAAAAAAc-c/jzW47YxHuUw/s1600/20141118_122335.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/--GqJBqRYyWI/VHBBGO45sTI/AAAAAAAAc-c/jzW47YxHuUw/s1600/20141118_122335.jpg" height="326" width="400"></a></div>
<br>
В английском варианте Windows ошибка звучит так:<br>
0x800F0906 The source files could not be downloaded.<br>
Windows couldn't connect to the Internet to download necessary files. Make sure that you're connected to the Internet and click "Retry" to try again.<br>
<br>
<a href="http://www.dotnetblog.ru/2014/11/0x800f081f-0x800f0906-net-framework-35.html#more">Дальше »</a>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2431668099949260719.post-6845061938197549552014-11-15T20:55:00.000+03:002014-11-15T20:55:00.519+03:00Помещение текущей даты в переменную в .bat-файле.Недавно столкнулся с задачей, требующей ежедневного архивирования содержимого папки в архив вида "название файлаDD_MM_YYYY". Чтобы это сделать в одном батнике надо выполнить несколько действий:<div>
<br></div>
<div>
1. Понять как выводится дата в вашей локали. Для этого запускаем <b>CMD</b> и пишем <b>DATE/T</b>. Русская локаль -самая простая, в ней текущая дата выводится в виде 15.11.2014. В Английской, например, все несколько сложнее, там перед датой идет сокращенное название дня недели, например Sat 15.11.2014. На на данном этапе интересует та часть строки, которая содержит дату. Чтобы получить ее, на нужна сделать так:</div>
<div>
<br></div>
<div>
<b>for /f %%i in ('DATE/T') do set date=%%i </b></div>
<div>
<br></div>
<div>
или, если перед датой что-то находится, например Sat</div>
<div>
<br></div>
<div>
f<b>or /f "tokens=2" %%i in ('DATE/T') do set date=%%i</b></div>
<div>
<br></div>
<div>
2. Теперь нам нужно заменить точки или слеши в дате на подчеркивание.</div>
<div>
</div><a href="http://www.dotnetblog.ru/2014/11/bat.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-62596696544239689482014-11-13T10:05:00.001+03:002014-11-13T10:05:16.751+03:00Microsoft открыла исходные коды .Net CoreСегодня Microsoft открыла исходный код основных компонент ядра .Net. Все исходника выложены на GitHub под лицензией MIT, так что, теперь можете изучать исходники .Net без дополнительных телодвижений типа Relector, и использовать части кода в своих продуктах.<div>
Пока доступен код только нескольких компонент:</div>
<div>
<div>
<ul>
<li>ASP.NET 5</li>
<li>EntityFramework</li>
<li>.NET Core 5</li>
<li>.NET Compiler Platform ("Roslyn")</li>
</ul>
<div>
Но, Microsoft обещает скоро выложить еще.</div>
</div>
</div>
<div>
<br /></div>
<div>
Лежит все тут: <a href="https://github.com/Microsoft/dotnet">https://github.com/Microsoft/dotnet</a></div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-22693820750522963722014-11-06T16:15:00.004+03:002014-11-06T16:20:25.556+03:00Что такое EntityValidationErrors и как с ним бороться.При использовании Entity Framework вы можете столкнуться с ошибкой, гласящей "<span style="background-color: white; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 17.8048000335693px;">Validation failed for one or more entities. See 'EntityValidationErrors' property for more details." </span>Причина появления этой ошибки в большинстве случаев - банальна, либо вы забыли какие ограничения существуют на полях в вашей базе данных, либо, если БД в вашей компании занимается отдельный человек, то он вам забыл о чем-то сообщить. ;)<br>
<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-jE5_GDo2mqw/VFtzLsmJt_I/AAAAAAAAcwM/snG-q9vvuQw/s1600/err.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-jE5_GDo2mqw/VFtzLsmJt_I/AAAAAAAAcwM/snG-q9vvuQw/s1600/err.jpg" height="158" width="640"></a></div>
<br>
EntityValidationErrors - это коллекция объектов DbEntityValidationResult, каждый из которых содержит информацию об ошибках одной EF-сущности в виде объектов DbValidationError.<br>
На самом деле, ничего страшного в этой ошибке нет, и можно легко узнать в чем конкретно у нас ошибка в коде. Все, что для этого необходимо - это обернуться вызов метода SaveChanges() вот в такой блок try-catch:<br>
<br>
<a href="http://www.dotnetblog.ru/2014/11/entityvalidationerrors.html#more">Дальше »</a>Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2431668099949260719.post-40059390884498466992014-11-05T15:49:00.001+03:002014-11-05T15:49:05.875+03:00ASP.NET 4.5 и Unobtrusive Validation, Progressive Degradation и что это все нам дает.В ASP.NET 4.5 среди прочих нововведений, во всю начал применяться так называемый подход Unobtrusive JavaScript, то есть, "ненавязчивый JavaScript" и использование jQuery. Эта технология уже применяется в ASP.NET MVC, по-моему, с третьей версии, и вот, теперь дело дошло и до WebForms.<br>
<div>
<br></div>
<div>
Что же это за зверь "Unobtrusive JavaScript"? Это относительно новый подход к разработке клиентской части web-страниц, предполагающий несколько вещей:</div>
<div>
<br></div>
<div>
<ol>
<li>Отделение поведения (JavaScript) от структуры и представления (HTML/CSS). То есть, такой своеобразный вариант клиентского MVC.</li>
<li>Попытки избежать традиционных проблем JavaScript (т.е., максимально возвожная браузеро- и платформонезависимость и масштабируемость)</li>
<li>Использование подхода Graceful degradation, то есть приложение должно оставаться работоспособным при использовании даже старых браузеров возможно вообще не поддерживающих JavaScript.</li>
</ol>
<div>
В ASP.NET все эти принципы проявляются в виде Unobtrusive Validation, о которой я постараюсь вам рассказать применительно к общей концепции Unobtrusive JavaScript.</div>
</div>
<div>
<br></div>
<div>
В качестве примера давайте создадим простой web-приложение на ASP.NET 4.5 и добавим в него одну единственную страничку с текстовым полем, кнопкой и валидатором того, что текстовое поле заполнено. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-4fPj5Q28xcg/VFoPKDUIJ_I/AAAAAAAAcuE/5Y86VRknkZU/s1600/project_cofig2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-4fPj5Q28xcg/VFoPKDUIJ_I/AAAAAAAAcuE/5Y86VRknkZU/s1600/project_cofig2.jpg" height="308" width="640"></a></div>
<div>
<br></div>
<div>
Как вы, наверное, помните, в предыдущих версиях добавление валидатора влекло за собой добавление в код страницы целой простыни JavaScript кода. А что сейчас? Давайте попробуем запустить наш пример.</div>
<div>
</div><a href="http://www.dotnetblog.ru/2014/11/aspnet-45-unobtrusive-validation.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-70321169482080151042014-11-04T11:55:00.004+03:002014-11-05T11:23:02.843+03:00Замена пустого места на что-то осмысленное в GridView при отображении NULL-значений.Может быть, заголовок не передает всей идеи того, о чем я хочу рассказать, так что попробую объяснить ситуацию более подробно. Наверняка, многие из вас сталкивались с чем-то подобным.<br>
Итак, представьте, что у нас в базе данных есть табличка примерно такого вида. Для простоты дальнейшего повествования предлагаю считать, что все поля, кроме id - nullable, так что null может быть где угодно, а не только в поле job.<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-SgPmLcz--2o/VFh2Tq60xTI/AAAAAAAActU/aUbA_Uw8lu0/s1600/dbtable.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-SgPmLcz--2o/VFh2Tq60xTI/AAAAAAAActU/aUbA_Uw8lu0/s1600/dbtable.jpg" height="125" width="400"></a></div>
<br>
И мы хотим вывести данные из нее в GridView. По умолчанию у нас получится вот что:<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-rEbT8gCWmlc/VFh26sk0BiI/AAAAAAAActc/PyHyYnjWvzw/s1600/site_table1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-rEbT8gCWmlc/VFh26sk0BiI/AAAAAAAActc/PyHyYnjWvzw/s1600/site_table1.jpg" height="229" width="400"></a></div>
<br>
Не красиво, и не очень информативно, согласитесь. Было бы более наглядно, если бы вместо пустого места вместо NULL-значений выводилось что-то более осмысленное и говорящее пользователю об истинном положении вещей.<br>
<br>
Сделать это можно двумя способами. Первый способ, для нашей задачи не очень правильный, путем создания обработчика события RowDataBound:<br>
<br>
<a href="http://www.dotnetblog.ru/2014/11/gridview-null.html#more">Дальше »</a>Unknownnoreply@blogger.com64tag:blogger.com,1999:blog-2431668099949260719.post-71344386215337401462014-10-11T22:12:00.001+04:002014-10-11T22:12:46.282+04:00COM Interop на примере работы с ExcelВ предыдущем посте я писал о создании csv-файла и экспорта в него данных из ASP.NET и при этом, перечисляя разные варианты, не упомянул один совсем уже бредовый для web-приложения, но частенько очень подходящий для приложений десктопных. Это работа с установленным в системе COM-объектом c помощью технологии под названием COM Interop.<br>
<br>
COM Interop используется в .Net для предоставления возможности взаимодействия управляемого .Net кода с COM-объектами. Тля того чтобы использовать какой-либо COM-объект из управляемого кода, необходимо создать сборку, содержащую информацию о типах содержащихся в COM-библиотеке, в совместимом с CRL формате.<br>
<br>
В процессе работы приложения CLR создает для каждого COM-объекта внутренний объект, называемый Runtime Callable Wrapper (Вызываемая оболочка времени выполнения) или RCW, которая используется для создания COM-объекта и маршалинга данных между управляемой и неуправляемой средой. Также, RCW используется для мониторинга количества активных ссылок на COM-объект и его уничтожение, когда количество активных ссылок станет равным нулю. Выглядит это примерно так:<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-lorVYsckZVA/VDleQ7pS2fI/AAAAAAAAckA/kfgixl8Il_E/s1600/inerop.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-lorVYsckZVA/VDleQ7pS2fI/AAAAAAAAckA/kfgixl8Il_E/s1600/inerop.jpg" height="163" width="400"></a></div>
Обычно, если вы ходите создать CLR библиотеку для какого-либо компонента самостоятельно, то вам нужно использовать утилиту Tlbimp.exe, но для использования компонентов Office этого делать не нужно. Все необходимые библиотеки уже устанавливаются вместе с продуктом. Нам достаточно только добавить нужную сборку в проект.<br>
<br>
<a href="http://www.dotnetblog.ru/2014/10/com-interop-excel.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-52594909234443020072014-10-10T11:18:00.002+04:002014-10-10T21:10:03.561+04:00Создаем .csv файлы в ASP.NETИногда возникает необходимость выгрузить какие-то данные в удобном для пользователя формате, который позволит на них не только смотреть, но и как-то обрабатывать и редактировать. Самым очевидным межплатформенным решением в таком случае видится форма CSV.<br>
<br>
Выгрузить CSV-файл с нужными данными можно несколькими способами:<br>
красивым и правильным, с использованием ASP.NET хэндлера (о хендлерах я как-нибудь напишу отдельно),<br>
изврашенным - написав консольное приложение, которое будет запускаться по определенному графику и создавать где-нибудь доступный для web-сервера файл,<br>
и простым и не очень правильным - просто изменив MIME-тип в ASPX-странице.<br>
Какой бы способ вы не выбрали, все сведется примерно к такому коду:<br>
<br>
<pre class="brush:csharp">
StringBuilder sb = new StringBuilder();
sb.AppendLine("1,2,3,4");
sb.AppendLine("5,6,7,8");
sb.AppendLine("9,10,11,12");
Response.ClearContent();
Response.Clear();
Response.ContentEncoding = Encoding.GetEncoding("Windows-1251");
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "attachment; filename=csvfile.csv;");
Response.Write(sb.ToString());
Response.Flush();
Response.End();
</pre>
<br>
Если у вас операционная система Windows и установлена англоязычная локаль, то все будет работать и вы не узнаете что есть небольшая проблема до того момента, пока кто-то из пользователей вам об этом не сообщит.<br>
<br>
<a href="http://www.dotnetblog.ru/2014/10/csv-aspnet.html#more">Дальше »</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2431668099949260719.post-58878223213914992292014-10-07T10:22:00.000+04:002014-11-07T15:46:46.663+03:00Как очистить таблицу с помощью Entity Framework.Если вы используете в своем проекте Entity Framework и хотите удалить все содержимое какой-либо таблицы не используя другие подключения к БД, кроме существующего, то можете использовать один из двух вариантов.<br />
<br />
Вариант первый. "Правильный" с точки зрения EF, так как при этом отслеживается состояние объектов. По этой же причине - более медленный.<br />
<br />
<pre class="brush:csharp">
context.YourTable.RemoveRange(context.YourTable);
context.SaveChanges();
</pre>
<br />
И второй способ. Менее "правильный", но зато быстрый. Если вам нужно очистить таблицу с какими-то временными, не имеющими отношений с другими объектами, то этот способ - самое оно.<br />
<br />
<pre class="brush:csharp"> context.Database.ExecuteSqlCommand("TRUNCATE TABLE [YourTable]");</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-6858149667013007412014-10-02T17:58:00.002+04:002014-10-02T17:58:27.795+04:00Сортировка случайных строк по одной из их частей.Недавно столкнулся с интересной задачей, общий смысл которой сводится к тому что мы получаем на вход массив строк, допустим, вида "1 тест","2 что-то еще написано", и этот список нужно вернуть отсортированным по, в данном случае, первой части строки - цифре. Хочу рассказать вам о решении, может быть, кому-то пригодится.<br>
<br>
Подводный камень номер один - производительность. Если использовать для выделения первой части строки string.Split(), то производительность падает пропорционально длине строк, раз, и размеру текста - два. Эту проблему можно решить, используя регулярные выражения.<br>
Например, для строк нашего типа можно сделать вот так:<br>
<br>
<pre class="brush:csharp">
string line = "1 тест";
string firstNumber = Regex.Match(line, "^(.*?)\s.*$").Groups[1].Value;
</pre>
<br>
Подробно о результатах сравнения производительности .Split() и Regex я напишу в отдельном посте, а сейчас продолжим. Итак, мы получили первый элемент строки, по которому нам нужно сортировать, теперь нужно придумать как сортировать строки.<br>
<br>
<a href="http://www.dotnetblog.ru/2014/10/blog-post.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-2907399136492401972014-09-29T18:29:00.001+04:002014-09-29T18:30:54.873+04:00Как программно сделать скриншот.Если когда-нибудь вам понадобиться программно сделать скриншот (ну, вдруг вы захотите облегчить жизнь пользователям и себе и решите делать скриншот автоматически в случае какой-то серьезной ошибки в вашем приложении), то нет ничего проще. Всего несколько строк кода и все готово:<br />
<br />
<pre class="brush:csharp">
Bitmap screen;
//в начале, нам надо получить размеры экрана.
Rectangle screenDimensions = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
Size s = new Size(screenDimensions.Width, screenDimensions.Height);
//и создать соответствующее пустое изображение.
screen = new Bitmap(s.Width, s.Height);
Graphics memoryGraphics = Graphics.FromImage(screen);
//вуаля! делаем скриншот.
memoryGraphics.CopyFromScreen(0, 0, 0, 0, s);
//и сохраняем в файл.
screen.Save("any_filename_you_like.jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
</pre>
<br />
<br />
PS. Да, не забудьте подключить пространство имен System.Drawing.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2431668099949260719.post-65336737443092649482014-09-22T12:04:00.001+04:002014-09-22T20:54:01.542+04:00Печатаем текст вертикально снизу вверх.Если у вас возникнет необходимость напечатать на странице вертикальный текст идущий снизу вверх, то вы будете не приятно удивлены. Такой возможности в .Net нет. Напечатать вертикальный текст сверху-вниз элементарно, это делается буквально в пару строк:<br>
<pre class="brush:csharp">
StringFormat formatver = new StringFormat(StringFormatFlags.DirectionVertical);
e.Graphics.DrawString("Проверка", this.Font, Brushes.Black, 0, 150, formatver);
</pre>
<br>
<br>
В результате получаем вот такой текст (1). Напечатать же текст (2) не прибегая к разным ухищрениям невозможно.<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-9K631b2_yxE/VB_VYYKLoOI/AAAAAAAAcA8/gOxBkHOvhbM/s1600/20140922_114728.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-9K631b2_yxE/VB_VYYKLoOI/AAAAAAAAcA8/gOxBkHOvhbM/s1600/20140922_114728.jpg" height="400" width="300"></a></div>
<br>
В сети есть разные варианты решения этой проблемы в основном сводящиеся к вращению холста с помощью Graphics.Transform. Такое решение, конечно, имеет право на жизнь, но оно, как мне кажется, далеко не самое оптимальное.<br>
<br>
<a href="http://www.dotnetblog.ru/2014/09/blog-post.html#more">Дальше »</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-34176526103713035492014-08-11T17:09:00.001+04:002014-08-11T17:09:30.997+04:00Как сделать сортировку по умолчанию в GridViewЕсли вам нужно чтобы данные в привязанном к данным (databound) GridView были по умолчанию как-то отсортированы, то, для того чтобы найти быстрое и правильное решение достаточно вспомнить о существовании у GridView такого свойства как SortExpression, которое содержит название столбца по которому в данный момент произведена сортировка. Соответственно, если данные не отсортированы, то SortExpression будет содержать пустое значение.<br />
Таким образом, проверяя в Page_Load это свойство может понять является ли текущее состояние грида состоянием по умолчанию или сортировка уже применена. Если же сортировка отсутствует, то мы можем применить необходимую нам по умолчанию. Например, вот так:<br />
<br />
<pre class="brush:csharp">
protected void Page_Load(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(GridView1.SortExpression))
GridView1.Sort("recordDate", SortDirection.Descending);
}
</pre>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2431668099949260719.post-77493597034017916362014-07-24T11:24:00.001+04:002015-01-19T09:36:16.192+03:00Функции ранжирования в MS SQL Как вы наверняка знаете, в реляционных базах данных строки в таблице не имеют порядка. Можно, конечно, использовать дополнительные механизмы, например IDENTITY-столбец, но это все равно не поможет вам получить, например, порядок строки в результатах запроса. Для возможности как-то соотносить порядок одних строк с другими и придуманы функции ранжирования. Прежде чем я перейду к рассказу о них, отмечу один важный момент: все ранжирующие функции являются недетерминированными, то есть результат их выполнения каждый раз может быть разным (хотя, на одном и том же наборе данных, один и тот же запрос будет возвращать один и тот же результат).<br>
<br>
Итак, собственно, функции ранжирования. Представим, что у нас есть вот такая табличка:<br>
<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-pvX9mhurk_Y/U9Cr840hjTI/AAAAAAAAbX0/5h3Ps-CwWd4/s1600/rownum1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-pvX9mhurk_Y/U9Cr840hjTI/AAAAAAAAbX0/5h3Ps-CwWd4/s1600/rownum1.jpg" height="116" width="400"></a></div>
<br>
И мы хотим получить порядок строк отсортированных по типу оборудования. Для этого можно использовать функция ROW_NUMBER().<br>
<br>
<pre class="brush: sql">SELECT ROW_NUMBER() OVER (ORDER BY PositionType DESC) as RowNumber
,[maker]
,[positionName]
,[positionType]
,[price]
FROM [test].[dbo].[rowNumbering]
</pre>
<br>
В результате выполнения этого запроса мы получим вот такой результат:<br>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-1kdKIeDhvp4/U9Cu9AaRmSI/AAAAAAAAbYA/Ititlyn15iU/s1600/rownum_rownum.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-1kdKIeDhvp4/U9Cu9AaRmSI/AAAAAAAAbYA/Ititlyn15iU/s1600/rownum_rownum.jpg" height="107" width="400"></a></div>
<br>
Как вы заметили, для указания на базе какого столбца будет сделана нумерация в запросе используется конструкция ORDER BY. На больших наборах данных из-за этого может пострадать производительность, но, если порядок следования рядов в результате выдачи вам не важен, то сортировки можно избежать, используя примерно такую конструкцию:<br>
<br>
<pre class="brush: sql">SELECT ROW_NUMBER() OVER (ORDER BY (SELECT TOP 1 1 FROM [test].[dbo].[rowNumbering])) as RowNumber
,[maker]
,[positionName]
,[positionType]
,[price]
FROM [test].[dbo].[rowNumbering]
</pre>
<br>
<br>
<a href="http://www.dotnetblog.ru/2014/07/ms-sql.html#more">Дальше »</a>Unknownnoreply@blogger.com0