вторник, августа 21, 2012
среда, июля 11, 2012
VirtualBox машина, доступная по WiFi снаружи (VirtualBox machine available outside using WiFi connection)
Тот же самый IP мы можем увидеть, используя ipconfig и рассмотрев подключение Wireless LAN adapter.
Потребуется настроить файрволл на гостевой ОС, в простейшем случае его можно просто отключить, и пробуем пропинговать нашу виртуалку, используя WiFi. В случае с iOS я установил бесплатную утилиту Free Ping, пингуем:
четверг, марта 29, 2012
Верх насилия над собой (или как отпилить сук, на котором сидишь) - 2
пятница, ноября 11, 2011
iPad 2 Тихий звук в наушниках
Уже подумал было, что возможен производственный брак (тем более, есть оказывается и у девайсов от такого известного производителя дефекты, о чем можно убедиться немного погуглив), как нарыл решение - оно оказалось простым и наверняка о нем знает каждый уверенный пользователь iPad:
Идем в настройки, раздел Музыка, видим там чекбокс на ограничение громкости, снимаем его и выставляем в слайдере максимальное значение, которое хотим - далее можно глохнуть в наушниках настолько насколько мы этого хотим :)
пятница, октября 07, 2011
Regex для распарсивания выражений с форматирующей маской {name: formatMask, formatLength}
Привожу код такого regex:
\{\s*(?<FieldExpression>\s*(?<FieldName>\w{1,}){1}\s*(?<FormatExpression>(\s*(?<ColonSeparator>[:])|(?<CommaSeparator>[,]))\s*(?(ColonSeparator)(?<FormatMask>\w*)|)[,]*\s?(?<Length>\d+)*)*)\s?\}
В группах имеем возможность получить сам fieldName, его маску fieldMask и длину length. Еще хочу отметить, что при работе с regex очень помогает такой инструмент как Rad Software Regular Expressions Designer -http://www.radsoftware.com.au/?from=RegexDesigner.
Пишем ajax available user control
Привет.
public partial class DemoUserControl : AjaxWebModule { #region demo methods here public AjaxResponse MyDemoMethod1(string arg1, string arg2, int arg3, bool arg4) { AjaxResponse result = new AjaxResponse { AdditionalSettings = String.Format("This is response to callback with parameters {0}/{1}/{2}/{3} from server side", arg1, arg2, arg3, arg4), CurrentPage = 0, Records = new List<object>() { new { Date = DateTime.Now, Data = int.MinValue } }, TotalRecords = 1, TotalPages = 1 }; return result; } public AjaxResponse MyDemoMethod2(int arg1, bool arg2) { AjaxResponse result = new AjaxResponse { AdditionalSettings = String.Format("This is response to callback with parameters {0}/{1} from server side", arg1, arg2), Records = new List<object>() { new { Date = DateTime.Now, Data = int.MinValue, OtherProperties = new List<object>{1, 2, 3} } } }; return result; } #endregion }
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="DemoUserControl.ascx.cs" Inherits="AjaxAvailableUserControls.Application.AjaxUserControls.DemoUserControl" %> <input type="button" onclick="click_handler();" value="click me to call server side method 1" id="btnDemo1"/><br /> <input type="button" onclick="click_handler();" value="click me to call server side method 2" id="btnDemo2"/><br /> <script language="javascript" type="text/javascript"> $(document).ready(function() { $("#btnDemo1").click(function() { jQuery.execute("MyDemoMethod1", { "arg1": "test string 1", "arg2": "test strign 2", "arg3": 2, "arg4": false }, { onSuccess: function (data) { debugger; alert("settings:" + data.AdditionalSettings + ";currentPage:" + data.CurrentPage.toString()); }, onError: function (exception) { alert(exception); } }); }); $("#btnDemo2").click(function () { jQuery.execute("MyDemoMethod2", { "arg1": 1, "arg2": false }, { onSuccess: function (data) { debugger; alert("settings:" + data.AdditionalSettings + ";currentPage:" + data.CurrentPage.toString()); }, onError: function (exception) { alert(exception); } }); }); }); </script>
{ "arg1": 1, "arg2": false } - (int arg1, bool arg2)
Как видно, со стороны клиента мы вызываем серверный метод MyDemoMetho1 и получаем результат в объектном виде, без всяких преобразований - магия :), более того, мы имеем возможность обработать как нормальное выполнение метода, так и его ошибку в случае какой-либо исключительной ситуации.
jQuery.execute("MyDemoMethod1", { "arg1": "test string 1", "arg2": "test strign 2", "arg3": 2, "arg4": false }, { onSuccess: function (data) { debugger; alert("settings:" + data.AdditionalSettings + ";currentPage:" + data.CurrentPage.toString()); }, onError: function (exception) { alert(exception); } });
Как видно, результат нормально десериализован, мы имеем на руках как обычные свойства объекта data, так и коллекцию вложенных объектов Records.
Собственно, все, надеюсь вам понравилась идея? Далее идет объяснение некоторых моментов.
Итак, в первую очередь нам важно, как реализован класс AjaxWebModule, именно он предоставляет возможность вызова серверного метода со стороны клиента.
Итак, его сигнатура:
/// /// Base class for all modules contained ajax logic /// public class AjaxWebModule : UserControl, ICallbackEventHandler { .................. }
/// <summary> /// Обрабатывает запрос со стороны клиента, вызывает соотвествующий метод из текущего модуля, формирует ответ, json-сериализует его в строку и /// отправляет обратно на клиента /// </summary> /// <param name="e"></param> private void ProcessRequest(ClientDataReceivedEventArgs e) { e.Cancel = false; // Данные со стороны клиента, передаваемые в качестве параметров в наш ajax метод // Параметры должны соотвествовать структуре класса AjaxRequestParameters // e.ClientData AjaxRequestParameters parameters = this.ParseParameters(e.ClientData); // вызов серверного ajax-метода AjaxResponse response = this.MethodInvoke(parameters); // Сериализованное состояние ответа от сервера, отправляемое клиенту в качестве ответа // e.ServerResponse // формируем ответ клиенту JavaScriptSerializer serializer = new JavaScriptSerializer(); e.ServerResponse = serializer.Serialize(response); }
Мы пока рассматриваем только серверную логику, до клиентской еще дойдем. Класс AjaxRequestParameters представляет собой следующее:
/// <summary> /// Параметры, передаваемый в ajax метод со стороны клиента /// </summary> public class AjaxRequestParameters { /// <summary> /// Имя вызываемого метода /// </summary> public string MethodName { get; set; } /// <summary> /// Список ЗНАЧЕНИЙ параметров, которые должны соотвествовать соотвествующим аргументам указанного метода - передаются со стороны клиента в виед пар Ключ-Значение /// </summary> public Dictionary<string, object> Parameters { get; set; } }
Код его приводить наверно нет смысла, он использует рефлексию для поиска метода с заданной сигнатурой, важно то,что возвращаемый результат искомого метода должен быть AjaxResponse.
Почему нам важна сигнатура возвращаемого результата? Только потому, что нам придется данный результат передавать на клиента, а чтобы его передать, нам нужно его сериализовать в строку, потому ответ от сервера должен отвечать определенным требованиям, а именно, он должен отвечать правилам сериализации. В данном примере я просто использовал простые типы данных для объвления интерфейса AjaxResponse, вы можете использовать другой интерфейс.
// Сериализованное состояние ответа от сервера, отправляемое клиенту в качестве ответа // e.ServerResponse // формируем ответ клиенту JavaScriptSerializer serializer = new JavaScriptSerializer(); e.ServerResponse = serializer.Serialize(response);
// core. client scripts library // created on 20111007 by smirnov andrey - duШes // #region execute extension method $.execute = function (methodName, parameters, options) { /// <summary> /// Вызывает серверный public-Метод текущего AjaxWebModule /// </summary> /// <param name="methodName" type="Object"> /// Аргумент methodName представляет собой имя вызываемого серверного метода, например, /// "DemoMethod2" /// </param> /// <param name="parameters" type="Object"> /// Объект parameters представляет собой хеш с указанием списка параметров в виде хеш - Имя параметра - Значение, например, /// { "id", 1 }, { "name", "test" } /// </param> /// <param name="options" type="Object"> /// Объект options представляет собой хеш с указанием OnSuccess handler в случае успешного завершения вызова и OnErrorHandler в случае ошибки, например /// { /// onSuccess: function(data) { /// alert(deserialized_request.AdditionalSettings); /// } /// onError: function(data) { /// alert("Exception thrown"); /// } /// </param> /// <returns type="undefined"> var settings = jQuery.extend({ control_id: null, onSuccess: function (data) { }, onError: function (data) { alert("Exception thrown ->" + data); } }, options || {}); var localOnSuccessHandler = function (data) { /// <summary> /// Данная функция является callback функцией, которая вызывается в случае успешного завершения внутреннего вызова ajaxRequest /// </summary> /// <param name="data" type="String"> /// Результат в виде строки - сериализованное состояние объекта-ответа со стороны серверной части /// </param> /// <returns type="undefined" /> var deserialized_request = $.JSON.decode(data); settings.onSuccess(deserialized_request); } var localOnErrorHandler = function (exception) { /// <summary> /// Данная функция является callback функцией, которая вызывается в случае НЕуспешного завершения внутреннего вызова ajaxRequest /// </summary> /// <param name="data" type="String"> /// Результат ошибки в виде строки /// </param> /// <returns type="undefined" /> settings.onError(exception); } var arrayParameters = []; $.each(parameters, function (name, value) { var wrapperParameter = { "Key": name, "Value": value }; arrayParameters.push(wrapperParameter); }); var request = { MethodName: methodName, Parameters: arrayParameters }; ajaxRequest(settings.control_id, request, localOnSuccessHandler, localOnErrorHandler); } // #endregion
var settings = jQuery.extend({ control_id: null, onSuccess: function (data) { }, onError: function (data) { alert("Exception thrown ->" + data); } }, options || {});
var localOnSuccessHandler = function (data) { /// <summary> /// Данная функция является callback функцией, которая вызывается в случае успешного завершения внутреннего вызова ajaxRequest /// </summary> /// <param name="data" type="String"> /// Результат в виде строки - сериализованное состояние объекта-ответа со стороны серверной части /// </param> /// <returns type="undefined" /> var deserialized_request = $.JSON.decode(data); settings.onSuccess(deserialized_request); }
var localOnErrorHandler = function (exception) { /// <summary> /// Данная функция является callback функцией, которая вызывается в случае НЕуспешного завершения внутреннего вызова ajaxRequest /// </summary> /// <param name="data" type="String"> /// Результат ошибки в виде строки /// </param> /// <returns type="undefined" /> settings.onError(exception); }
Теперь уже осталось немного, мы дошли до подготовки наших данных для отправки на сервер, здесь подгатавливаем объект request, в котором мы указали имя метода и список его параметров.
Помните класс AjaxRequestParameters на серверной стороне? да, это именно его представление, в объект класса AjaxRequestParameters может быть преобразован данный объект со стороны клиента.
var arrayParameters = []; $.each(parameters, function (name, value) { var wrapperParameter = { "Key": name, "Value": value }; arrayParameters.push(wrapperParameter); }); var request = { MethodName: methodName, Parameters: arrayParameters };
Все готово, вызываем ajaxRequest:
ajaxRequest(settings.control_id, request, localOnSuccessHandler, localOnErrorHandler);
Стоп, что это !!! что это за ajaxRequest такой?!!
А формируется оно в уже рассмотренном нами классе AjaxWebModule:
/// <summary> /// Имя функции, которая будет использоваться для вызова серверного сценария со стороны клиента, принимает один аргумент ARG в виде строки /// </summary> [Browsable(true)] [Category("Callback Handlers")] [DefaultValue("serverCall")] [Description("Имя функции, которая будет использоваться для вызова серверного сценария со стороны клиента, принимает один аргумент ARG в виде строки ")] public string ServerCallFunctionName { get { return "ajaxRequest"; } } protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); #region регистрация server callback function со стороны клиента - здесь формируем wrapper на функцией WebFormdoCallback if (!this.Page.ClientScript.IsClientScriptBlockRegistered(this.Page.GetType(), "AjaxRequestWebFormDoCallbackScript")) { string webFormDoCallbackScript = this.Page.ClientScript.GetCallbackEventReference("control_id", "serialized_request", "localOnSuccessHandler", null, "localOnErrorHandler", true); string serverCallScript = "function " + this.ServerCallFunctionName + "(control_id, arg, localOnSuccessHandler, localOnErrorHandler){" + "\r\n" + "var serialized_request = $.JSON.encode(arg);\r\n" + "if (typeof(control_id) == 'undefined' || control_id == null)\r\n" + String.Format("{{ control_id='{0}';}}\r\n", this.UniqueID) + webFormDoCallbackScript + ";\n}\n"; this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "AjaxRequestWebFormDoCallbackScript", serverCallScript, true); } #endregion #region WebformDoCallback script registration // fix проблемы описанной http://www.codeproject.com/KB/aspnet/pendingcallbacks.aspx // регистрируем функцию WebForm_CallbackComplete_SyncFixed, в которой нет ошибки с обращение к переменной i в цикле for string callbackCompleteFixScriptName = "WebForm_CallbackComplete_SyncFixed"; string callbackCompleteFixScript = @" function WebForm_CallbackComplete_SyncFixed() { // the var statement ensure the variable is not global for (var i = 0; i < __pendingCallbacks.length; i++) { callbackObject = __pendingCallbacks[i]; if (callbackObject && callbackObject.xmlRequest && (callbackObject.xmlRequest.readyState == 4)) { if (!__pendingCallbacks[i].async) { __synchronousCallBackIndex = -1; } __pendingCallbacks[i] = null; var callbackFrameID = '__CALLBACKFRAME' + i; var xmlRequestFrame = document.getElementById(callbackFrameID); if (xmlRequestFrame) { xmlRequestFrame.parentNode.removeChild(xmlRequestFrame); } WebForm_ExecuteCallback(callbackObject); } } } "; if (!this.Page.ClientScript.IsClientScriptBlockRegistered(this.Page.GetType(), callbackCompleteFixScriptName)) { this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), callbackCompleteFixScriptName, callbackCompleteFixScript, true); } // заменяем функцию WebForm_CallbackComplete на нашу WebForm_CallbackComplete_SyncFixed и регистрируем ее на момент // полной загрузки страницы string onloadScriptName = "pageload_callback_complete_fix"; string onloadScript = @" if (typeof (WebForm_CallbackComplete) == 'function') { WebForm_CallbackComplete = WebForm_CallbackComplete_SyncFixed; } "; if (!this.Page.ClientScript.IsStartupScriptRegistered(callbackCompleteFixScriptName)) { this.Page.ClientScript.RegisterStartupScript(this.GetType(), onloadScriptName, onloadScript, true); } #endregion }
Если мы посмотрим исходный код нашей страницы, то увидим результат выполнения OnPrerender:
function ajaxRequest(control_id, arg, localOnSuccessHandler, localOnErrorHandler){ var serialized_request = $.JSON.encode(arg); if (typeof(control_id) == 'undefined' || control_id == null) { control_id='ctl00$Content$DemoUserControl1';} WebForm_DoCallback(control_id,serialized_request,localOnSuccessHandler,null,localOnErrorHandler,true); }
Собственно, здесь как раз и происходит "заворачивание" нашего "объектного" вызова в строку и передача его в WebForm_DoCallback.
Сигнатура данного метода подробно описана как в msdn, так и у меня в статьях по выполнения cakkback со стороны клиента ранее.
Передача параметров туда и обратно осталось такой же - а именно - только путем передачи строковых значений.
Мы же просто обернули все это в красивую оболочку, которой будет приятно пользоваться, но понимание того, как это все работает, важно. Вы можете расширить возможности данного подхода, например, для поддержки какого-то jQuery ui-контрола, например, грида и прочее.
Нужен этот параметр только для того, чтобы разделить вызовы из разных user controls, т.е. в том случае, когда на странице есть несколько user controls, из клиенских скриптов которых осуществляется вызов серверных методов, причем, сигнатура их может быть совпадать. Или, в том случае, когда на странице два инстанса нашего ajax available user control - тут нам и пригодится controlid, чтобы разделить вызовы, идущие к конкретному инстансу user control. Делается это так:
jQuery.execute("DemoMethod1", { "id": 1, "name": "testName" }, { control_id: '<%= UniqueID %>', onSuccess: function(data) { alert("settings:" + data.AdditionalSettings + ";currentPage:" + data.CurrentPage.toString()); }, onError: function(exception) { alert(exception); } });
среда, сентября 28, 2011
SharePoint 2010 unit testing in Visual Studio 2010
Бля ну что за лажа с шарпоинт, точнее даже не с ним :) (не кидайте камнями, решение внизу)
Вдруг выяснилось, что нельзя написать ms test targeted to .net 3.5 в Visual Studio 2010, чтобы написать парочку тестов, связанных с sharepoint 2010.
В конечном итоге так и придется использовать какие-нить тулзы типа nUnit...
Ладно, в любом случае в процессе гуглинга надыбал интересную фишку, а именно, все же можно заставить ms test выполняться в x64 mode.
Подробности здесь
http://msdn.microsoft.com/en-us/library/ee782531.aspx
что удивительно, описание в картинках, вот так бы почаще :)
Достучаться до этого диалога можно, находясь в контексте ms тестового проекта:
Как выяснилось, решение все же есть:
http://msdn.microsoft.com/en-us/library/gg601487.aspx
Testing SharePoint 2010 Applications
The capabilities listed above also enable you to write unit tests and integration tests for SharePoint 2010 applications using Visual Studio 2010 Service Pack 1. For more information about how to develop SharePoint 2010 applications using Visual Studio 2010, see SharePoint Development in Visual Studio, Building and Debugging SharePoint Solutions and Verifying and Debugging SharePoint Code by Using ALM Features.
Limitations
The following limitations apply when you re-target your test projects to use the .NET Framework 3.5:
In the .NET Framework 3.5, multitargeting is supported for test projects that contain only unit tests. The .NET Framework 3.5 does not support any other test type, such as coded UI or load test. The re-targeting is blocked for test types other than unit tests.
Execution of .NET Framework 3.5 tests is supported only in the default host adapter. It is not supported in the ASP.NET host adapter. ASP.NET applications that have to run in the ASP.NET Development Server context must be compatible with the .NET Framework 4.
Data collection support is disabled when you run tests that support .NET Framework 3.5 multitargeting. You can run code coverage by using the Visual Studio command-line tools.
Unit tests that use .NET Framework 3.5 cannot run on a remote machine.
В описании сервис-пака:
http://support.microsoft.com/kb/983509
Basic Unit Testing support for the .NET Framework 3.5
In Visual Studio 2010 SP1, you now have the functionality to test your applications that target the .NET
Итак, поехали, сервиспак радостно качаем отсюда:
http://www.microsoft.com/download/en/confirmation.aspx?id=23691
Теперь выставляем targetting framwework в .net 3.5, хост выполнения теста в x64 mode:
Наслаждаемся:
Будут вопросы, пишите :) Будет время, отвечу :)
четверг, июля 21, 2011
пятница, июля 08, 2011
[Window Server 2008, SharePoint 2010, Visual Studio, TFS] How to connect to TFS with different user credentials
Собственно, потребовалось подключиться к TFS под другим аккаунтом, оказалось, это достаточно проблематично, если сама студия уже сохранила user credentials.
Никакого диалога в студии вы не найдете, попытки disconnect в team viewer и обратный connect ничего не дадут, вы будете работать под предыдущим аккаунтом.
Проблема рассматривалась также вот здесь:
Connect to TFS with different user credentials
но мне как-то это не сильно помогло, итак мой рецепт, как это лечить:
1. Идем в control panel, фильтруем по manage passwords:
2. Далее, manage windows credentials:
Здесь видим тот аккаунт, который windows будет использовать по умолчанию для доступа к TFS:
Делаем Remove from vault, перегружаем студию, в следующей попытке сделать connect to TFS студия запросит новый аккаунт.
Кеширование аккаунта происходит по той причине, что мы сами его и сохраняем, когда выбираем чекбокс Remember my credentials:
среда, марта 31, 2010
Тесты и Exception вида "System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used"....
<Execution parallelTestCount=""<вставить нужное="" значение="">
если parallelTestCount == 0, то тесты выполняются параллельно, количество тестов в пуле выбирается самой студией...
Мне же был нужен следующий вариант:
<TestSettings name="Local" id="38863d1e-30b7-4b4a-a629-4add84f4982e" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"> <Description>These are default test settings for a local test run.</Description> <Execution parallelTestCount="1"> <TestTypeSpecific /> <Timeouts runTimeout="900000" testTimeout="900000" /> <ExecutionThread apartmentState="MTA"/> <AgentRule name="Execution Agents"> </AgentRule> </Execution> </TestSettings>
Важно: чтобы ваши изменения вступили в силу, нужно перегрузить проект/решение;
ps: попутно читал следующие ресурсы:
http://connect.microsoft.com/VisualStudio/feedback/details/534124/exception-running-tests-that-use-waithandle-waitall-waithandles
VS2010 tip: How to run unit tests in parallel
http://blogs.microsoft.co.il/blogs/dhelper/archive/2010/03/02/vs2010-tip-how-to-run-unit-tests-in-parallel.aspx
Parallel Test Execution in Visual Studio 2010
http://msmvps.com/blogs/p3net/pages/parallel-test-execution-in-visual-studio-2010.aspx
Executing Unit Tests in parallel on a multi-CPU/core machine
http://blogs.msdn.com/vstsqualitytools/archive/2009/12/01/executing-unit-tests-in-parallel-on-a-multi-cpu-core-machine.aspx