Subscribe RSS

Polskie blogi specjalistów IT / Microsoft

agregator blogów
  • O usłudze
  • ziembor.pl/blog/
  • Gdzie szukam?
    • wss.pl
    • ITBlogs
    • Jogger Techblog
    • dobreprogramy
  • Inne agreagatory
    • zine.net.pl/TechBlogs
    • itblogs.pl/agregat/

Author: Mateusz Świetlicki


Office 365 Powershell – Zmiana daty wygasania hasła

2012-04-04 Posted by Mateusz Świetlicki under Polskie blogi IT

http://www.thomasmaurer.ch/2011/07/office-365-how-to-connect-with-powershell/

http://www.thomasmaurer.ch/2011/10/change-office-365-password-expiration-policy/

 

Office365 – PassNeverExpires for All.ps1 (554,00 bytes)

MVC MessageBox (bez JS)

2012-03-24 Posted by Mateusz Świetlicki under MVC, Polskie blogi IT, Twórczość

Nie jestem pewien czy to w ogóle dobra praktyka, ale ubzdurałem sobie ostatnio, że fajnie mieć akcję kontrolera która będzie wyświetlać wiadomości w stylu “Sukces, wróć do strony głównej”.

Mimo tego, że może niekoniecznie jest to dobry pomysł to nauczyłem się trochę starając się to napisać, a to opis mojego rozwiązania:

Na początek w kontrolerze Home dodałem akcję:

public ActionResult MessageBox(string title, string body)
{

    ViewBag.MsgTitle = title;
    ViewBag.MsgBody = body;

    return View();
}

Którą wywołując to przez:

RedirectToAction("MessageBox",
                 "Home",
                 new RouteValueDictionary()
                 {
                    {"title", "Tytuł"},
                    {"body", "Wiadomość."}
                 });

Z tym rozwiązaniem są jednak 2 problemy. Po pierwsze w tej formie title i body wysyłane są w adresie metodą GET, po drugie wywołanie wykorzystuje chronioną metodę RedirectToAction klasy Controller:

protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName);

Przez co nie można użyć jej w statycznej funkcji w jakichś Utils’ach.

Rozwiążemy te problemy po kolei. Do przesłania title i body zamiast RouteValueDictionary możemy użyć ControllerBase.TempData które pozwalają na przesłanie danych do następnego zapytania. Uzyskamy wtedy:

/// <summary>
/// Place title into TempData["MsgTitle"]
/// Place body into TempData["MsgBody"]
/// </summary>
/// <returns></returns>
public ActionResult MessageBox()
{
    ViewBag.MsgTitle = TempData["MsgTitle"].ToString();
    ViewBag.MsgBody = TempData["MsgBody"].ToString();

    return View();
}

i

TempData["MsgTitle"] = title;
TempData["MsgBody"] = body;
return RedirectToAction("MessageBox", "Home");

Problem nr 2 (protected RedirectToAction)  pewnie można rozwiązać na kilka sposobów. Moja pierwszą próbą było użycie:

HttpContext.Response.Redirect("~/Home/MessageBox");

Niestety użycie Response.Redirect nie jest kompatybilne z TempData. Dlatego zdecydowałem się użyć starego i trochę nieprzewidywalnego tricku z użyciem Refleksji. Otóż metody prywatne wciąż mogą być wywołane z dowolnego miejsca, trzeba jedynie użyć parametrów BindingFlags.NonPublic i BindingFlags.Instance metody Type.GetMethod. Ostatecznie powstało więc takie zręczne rozszerzenie:

public static class ControllerExtensions
{
    public static ActionResult RedirectToMessageBox(this Controller controller, string title, string body)
    {
        controller.TempData["MsgTitle"] = title;
        controller.TempData["MsgBody"] = body;

        var redirect = controller.GetType().GetMethod("RedirectToAction",
                                                        BindingFlags.NonPublic | BindingFlags.Instance,
                                                        null,
                                                        new Type[] { typeof(string), typeof(string) },
                                                        null);
        return redirect.Invoke(controller, new object[] { "MessageBox", "Home" }) as ActionResult;
    }
}

Teraz mogę już przekierować przekierować do ekranu MessageBox z dowolnego kontrolera prostą metodą:

return this.RedirectToMessageBox("Tytuł", "Wiadomość.");

Pozdrawiam.

ASP.NET MVC i Entity Framework–Jedna instancja na zapytanie

2012-03-22 Posted by Mateusz Świetlicki under Dobre praktyki, Entity Framework, Polskie blogi IT

Piszą aplikację webową z użyciem Entity Framework prędzej czy później natrafi się na problem z ilością instancji naszego DbContext.

Prawie wszystkie przykłady pokazują aby robić po prostu:

MyDbContext db = new MyDbContext();

W każdym kontrolerze. Co działa, ale szybko okazuje się problematyczne gdy chcemy tworzyć funkcje wspólne dla wielu kontrolerów albo gdy chcemy wykonywać biznesowe operacje wewnątrz modelu.

Weźmy na przykład statyczną metodę Create dla obiektu modelu (którą z jakiegoś powodu chcielibyśmy napisać):

class House
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Window> Windows { get; set; }

    public House()
    {
        Windows = new List<Window>();
    }

    public static House Create()
    {
        var house = new House() { Name = "Domek" };
        var db = new MyContext();

        db.Houses.Add(house);

        db.SaveChanges();

        return house;
    }
}

Jeśli spróbowalibyście teraz wykorzystać obiekt klasy House zwrócony przez tą funkcję okaże się wyskakują dziwne błędy np.:

MyContext context = new MyContext();
var house = House.Create();
context.Houses.Remove(house);
context.Dispose();

Zakończy się błędem:

The object cannot be deleted because it was not found in the ObjectStateManager.

Jest to związane z tym, że nie wolno współdzielić obiektów między instancjami DbContext. Więc pierwszą myślą mogło by być “Stwórzmy pojedynczą Singletonową instancję MyContext!”. Tak, tak to nie też nie jest mądre.

class MyContext: DbContext
{
    static MyContext _singleton;
    public static MyContext Singleton
    {
        get { return _singleton ?? (_singleton = new MyContext()); }
    }

    public DbSet<House> Houses { get; set; }
    public DbSet<Window> Windows { get; set; }
}

Podejście Singleton będzie działać i rozwiąże wcześniejsze problemy, ale po chwili spotkamy się z jeszcze trudniejszymi problemami jak znikające dane, nieodświerzające się kolekcje, wielowątkowe blokady czy błędy przy SaveChanges().

Najlepszym rozwiązaniem do jakiego ja doszedłem jest tworzenie 1 instancji na 1 wątek/HttpContext/Jednostę pracy.

private static PasDb _pasDb;

public static void SetStaticCurrent(PasDb current)
{
    _pasDb = current;
}

public static PasDb Current
{
    get
    {
        if (HttpContext.Current == null)
            return _pasDb ?? (_pasDb = new PasDb());

        if (HttpContext.Current.Items.Contains("db"))
            return HttpContext.Current.Items["db"] as PasDb;

        return (HttpContext.Current.Items["db"] = new PasDb()) as PasDb;
    }
}

protected override void Dispose(bool disposing)
{
    if (_pasDb == this)
        _pasDb = null;
    else if (HttpContext.Current.Items.Contains("db"))
        HttpContext.Current.Items.Remove("db");
    base.Dispose(disposing);
}

statyczne _PasDb jest przydatny dla testów i w szczególnych wypadkach.

 

PS:

To z jakiegoś powodu wydało mi się powiązane z tematem ;P

To z jakiegoś powodu wydało mi się powiązane z tematem ;P

EF CodeFirst cascade delete

2012-03-21 Posted by Mateusz Świetlicki under Entity Framework, Polskie blogi IT

Standardowym zachowaniem EntityFramework CodeFirst jest brak akcji w przypadku usunięcia obiektu powiązanego relacją jeden-do-wielu. Powoduje pozostawienie wpisów z Null w foreign key.

Oto przykład:

class House
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Window> Windows { get; set; }

    public House()
    {
        Windows = new List<Window>();
    }
}
class Window
{
    [Key]
    public int Id { get; set; }
    public int Size { get; set; }

    public virtual House House { get; set; }
}
class MyContext: DbContext
{
    public DbSet<House> Houses { get; set; }
    public DbSet<Window> Windows { get; set; }
}
class Program
{
    static void PrintHousesAndWindows(MyContext context)
    {
        Console.WriteLine();
        Console.WriteLine("Number of houses: " + context.Houses.Count());
        Console.WriteLine("Number of windows: " + context.Windows.Count());
        Console.WriteLine();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Start");
        MyContext context = new MyContext();

        PrintHousesAndWindows(context);

        Console.WriteLine("Adding house...");
        var house = new House() { Name = "My house" };
        context.Houses.Add(house);

        Console.WriteLine("Adding windows...");
        house.Windows.Add(new Window() { Size = 150 });
        house.Windows.Add(new Window() { Size = 200 });

        Console.WriteLine("Saving...");
        context.SaveChanges();

        PrintHousesAndWindows(context);

        Console.WriteLine("Removing house...");
        context.Houses.Remove(house);
        context.SaveChanges();

        PrintHousesAndWindows(context);

        Console.WriteLine("Finish");
        Console.ReadLine();
    }
}

Wynik programu jest następujący:

Start

Number of houses: 0
Number of windows: 0

Adding house...
Adding windows...
Saving...

Number of houses: 1
Number of windows: 2

Removing house...

Number of houses: 0
Number of windows: 2

Finish

A gdy spojrzymy w bazę danych okaże się, że House_Id w wierszach tabeli Windows jest równy NULL.

Id	Size	House_Id
1	150	NULL
2	200	NULL

Aby wymusić usuniecie obiektów klasy Windows z bazy wystarczy dodać atrybut Required przez właściwością House klasy Window.

class Window
{
    [Key]
    public int Id { get; set; }
    public int Size { get; set; }

    [Required]
    public virtual House House { get; set; }
}

Oczywiście po zmianie modelu przez uruchomieniem programu musimy usunąć potrzednie wpisy i wywołać automatyczną migrację

update-database -force

Więcej o CodeFirst Migrations tutaj

Teraz wynik programu wygląda następująco:

Start

Number of houses: 0
Number of windows: 0

Adding house...
Adding windows...
Saving...

Number of houses: 1
Number of windows: 2

Removing house...

Number of houses: 0
Number of windows: 0

Finish

Jak widzimy usunięcie House usunęło także Windows.

Jest jeszcze możliwość kontroli cascade delete przy użyciu FluidAPI lub Convention nawet na opcjonalnych parametrach.

Web scraper, Czyli jak zautomatyzować Internet.–Pobieranie HTMLa

2012-03-20 Posted by Mateusz Świetlicki under Polskie blogi IT, Twórczość, Web scraping

Podstawowa obsługa protokołu http i pobieranie treści stron internetowych w .NET jest bardzo prosta. Wystarczy użyć obiektu klasy WebClient. Tradycyjnie:

var WC = new WebClient();
string source = WC.DownloadString("http://www.codeguru.pl");

Lub asynchronicznie (WP7 czy C# 4.5):

var WC = new WebClient();
string source = await WC.DownloadStringAsync("http://www.codeguru.pl");

Niestety, WebClient zadziała tylko gdy używamy metody “GET”, czyli wpisujemy jedynie adres strony. Nie  pozwala np. na przesłanie formularza logowani,a które najczęściej wymagają metodę “POST”. Brakuje też kontroli ciasteczek, headerów i możliwości własnej obsługą kodów błędów.

Dlatego też użyjemy bardziej zaawansowanej klasy HttpWebRequest. Oto prosty przykład:

using System.Net;
using System.IO;

...

string source = DownloadWebPageString("http://www.codeguru.pl");

...

private static string DownloadWebPageString(string url)
{
    CookieContainer Cookies = new CookieContainer();
    HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(url);
    Request.Accept = "*";
    Request.Method = "GET";
    Request.CookieContainer = Cookies;
    Request.KeepAlive = true;
    Request.UserAgent = "Opera/9.80 (Windows NT 6.1; U; pl)";
    using (var Response = (HttpWebResponse)Request.GetResponse())
    {
        using (var SR = new StreamReader(Response.GetResponseStream()))
        {
            return SR.ReadToEnd();
        }
    }
}

Oczywiście podany kod nie obsługuje metody “POST” i brakuje mu obsługi błędów, dlatego też zamieszczę trochę pełniejszą klasę którą kiedyś (dawno temu) napisałem w tym celu:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

public class HTTPRequest
{
    public HTTPRequest()
    {
        Cookies = new CookieContainer();
    }

    public CookieContainer Cookies;
    private List<FormInput> ReqInput = new List<FormInput>();
    private List<FormInput> ReqHeader = new List<FormInput>();

    public string OpenSite(string URL, RequestENUM ReqType, string ContentType)
    {
        String response;
        Encoding enc = Encoding.Default;
        try
        {

            Stream s = OpenSiteToSR(URL, ReqType, ContentType);

            MemoryStream ms = new MemoryStream(); //TODO: Możę da się to zoptymlizować
            {
                int bytes = 0;
                byte[] temp = new byte[4096];
                while ((bytes = s.Read(temp, 0, temp.Length)) != 0)
                    ms.Write(temp, 0, bytes);

                temp = new byte[512];
                ms.Position = 0;
                ms.Read(temp, 0, 512);
                ms.Position = 0;

                string str = enc.GetString(temp);
                Match m = new Regex("charset=(?<ENC>.+?)[\"|>]").Match(str);
                if (m.Success) enc = Encoding.GetEncoding(m.Groups["ENC"].Value);
            }

            StreamReader SR = new StreamReader(ms, enc);
            response = SR.ReadToEnd();
            SR.Close();
        }
        catch (Exception e)
        {
            response = e.Message;
        }
        return response;
    }

    public Stream OpenSiteToSR(string URL, RequestENUM ReqType, string ContentType)
    {
        //Thread.CurrentThread.Name = "HTTPRequest event";

        string RequestSTR = GETRequest();

        if (ReqType == RequestENUM.HTTP_GET)
        {
            URL = URL + "?" + RequestSTR;
        }
        HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);
        HttpWebResponse Response;
        Stream SR;
        StreamWriter SW;

        // Prepare Request Object
        Request.Accept = "*";
        Request.Method = ReqType.ToString().Substring(5);
        Request.CookieContainer = Cookies;

        // Set form/post content-type if necessary
        if ((ReqType == RequestENUM.HTTP_POST && ReqInput.Count != 0 && string.IsNullOrEmpty(ContentType)))
        {
            ContentType = "application/x-www-form-URLencoded";
        }

        // Set Content-Type

        Request.KeepAlive = true;
        Request.UserAgent = "Opera/9.80 (Windows NT 6.1; U; pl)";

        if ((!string.IsNullOrEmpty(ContentType)))
        {
            Request.ContentType = ContentType;
            Request.ContentLength = RequestSTR.Length;
        }
        // Send Request, If Request
        if ((ReqType == RequestENUM.HTTP_POST))
        {
            try
            {
                SW = new StreamWriter(Request.GetRequestStream());
                SW.Write(RequestSTR);
                SW.Close();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        // Receive Response
        try
        {
            Response = (HttpWebResponse)Request.GetResponse();
            foreach (var item in Response.Headers)
            {
                string s = Response.GetResponseHeader(item.ToString());
            }
            SR = Response.GetResponseStream();
        }
        catch (Exception Ex)
        {
            throw Ex;
        }

        ClearInput();

        return SR;
    }

    public void AddInput(FormInput input)
    {
        ReqInput.Add(input);
    }

    public void AddInput(string name, string value)
    {
        AddInput(new FormInput(name.Trim(), value.Trim()));
    }

    public void AddHeader(string name, string value)
    {
        ReqHeader.Add(new FormInput(name.Trim(), value.Trim()));
    }

    public void ClearInput()
    {
        ReqInput.Clear();
        ReqHeader.Clear();

    }

    public string BildHtmlSite(string URL, RequestENUM ReqType)
    {
        StringBuilder SB = new StringBuilder();
        SB.AppendLine("<HTML>");
        SB.AppendLine("<body onLoad=\"document.formularz.submit();\">");
        SB.AppendLine("<form name=\"formularz\" action=\"" + URL + "\" method=\"" + ReqType.ToString().Substring(5) + "\">");
        int i = 0;
        for (i = 0; i < ReqInput.Count; i++)
        {
            SB.AppendLine("<input name=\"" + ReqInput[i].Name + "\" type=\"text\" value=\"" + ReqInput[i].Value + "\" />");
            SB.AppendLine("<br>");
        }
        SB.AppendLine("<input type=\"submit\" value=\"wyslij\" />");
        SB.AppendLine("</form>");
        SB.AppendLine("</body>");
        SB.AppendLine("</HTML>");

        return SB.ToString();
    }

    public string GETRequest()
    {
        StringBuilder SB = new StringBuilder();
        int i = 0;
        for (i = 0; i < ReqInput.Count; i++)
        {
            if (ReqInput[i].Name != string.Empty)
            {
                SB.Append(URLEncode(ReqInput[i].Name));
                SB.Append("=");
                SB.Append(URLEncode(ReqInput[i].Value));
                if (i != ReqInput.Count - 1) SB.Append("&");
            }
        }

        return SB.ToString();
    }

    private string URLEncode(string str)
    {
        return Uri.EscapeDataString(str);
    }

    private string UrlDecode(string str)
    {
        return Uri.UnescapeDataString(str);
    }

    public static List<FormInput> GetInputs(string source)
    {
        List<FormInput> lista = new List<FormInput>();
        Regex rinput = new Regex("<input.+name=\"(?<name>[^\"]+).*?>");
        Regex rinputvalue = new Regex("<input.+name=\"(?<name>[^\"]+).*?(value=\"(?<value>[^\"]*)).*?>");
        MatchCollection ms = rinput.Matches(source);

        foreach (Match item in ms)
        {
            FormInput i = null;
            Match m = rinputvalue.Match(item.ToString());
            if (m.Success)
            {
                i = new FormInput(m.Groups["name"].ToString(), m.Groups["value"].ToString());
            }
            else
            {
                i = new FormInput(item.Groups["name"].ToString(), "");
            }
            lista.Add(i);
        }
        return lista;
    }

}

public enum RequestENUM
{
    HTTP_GET = 0,
    HTTP_POST = 1
}

public class FormInput
{
    public string Name { get; set; }
    public string Value { get; set; }

    public FormInput() { }
    public FormInput(string name, string value)
    {
        Name = name;
        Value = value;
    }

    public override string ToString()
    {
        return string.Format("{0} = {1}", Name, Value);
    }
}

Polecam przeanalizowanie kodu i działania klas WebHttpRequest i WebHttpResponse.

Prawdopodobnie teraz trochę bym w tym kodzie poprawił, ale działa i na potrzeby tego kursu spokojnie wystarczy (Najwyżej będziemy coś łatać).

W następnym odcinku przedstawię kilka sposobów jak wyszukiwać interesujących nas informacji w całym śmietniku HTMLa.

ASP.NET MVC Globalizacja

2012-03-19 Posted by Mateusz Świetlicki under MVC, Polskie blogi IT

Globalizacja jest ważną częścią nowoczesnych portali internetowych (choć osobiście robiłbym wszystko po angielsku i się nie przejmował). Niestety w MVC 3 nie obędzie się bez problemów.

Oto moje rozwiązanie:

Dane językowe trzymamy w plikach:

/App_GlobalResources/Translation.resx
/App_GlobalResources/Translation.pl-PL.resx
/App_GlobalResources/Translation.en-US.resx
...

Pliki dodajemy zwyczajnie:

  1. Tworzymy w projekcie katalog “App_App_GlobalResources”
  2. Klikamy prawym i wybieramy “Add\New item”
  3. Wybieramy “Resources file”
  4. Wewnątrz pliku dodajemy unikatowe nazwy pól i tłumaczenia w różnych językach.

Niestety plik ten nie będzie działać dobrze z System.ComponentModel.DataAnnotations:

[Display(ResourceType = typeof(Translation), Name = "RadarDataTimeLabel")]
public DateTime DateTime { get; set; }

Wyskoczy przy uruchomieniu wyjątek:

CS0122: 'Translation' is inaccessible due to its protection level

Lub podobny o tym że ‘Translation’ nie jest publiczny.

Translation is not public or does not contain a public static string property with the name RadarDataTimeLabel

Naprawić można to wykorzystując trick z http://holyhoehle.wordpress.com/2010/02/20/making-global-resources-public czyli zamieniając Custom Tool na PublicResXFileGenerator i Build Action na Embedded Resource.

globalresourceaccess

Po tym jednak możemy się spodziewać wyjątku:

The type 'translation' exists in both ”XXX.dll“ and ”YYY.dll

Z tym poradzimy sobie zmieniając Namespace z ‘Resources’ na np. ‘MyProject.Web’.

Teraz aby wybrać konkretny język należy dodać wpis w web.config

<system.web>
    <globalization uiCulture="auto" culture="auto" />
...

Albo określić język w kodzie przez

Translation.Culture = new CultureInfo("pl-PL");

CodeFirst DbSet.AddOrUpdateByProperty

2012-03-16 Posted by Mateusz Świetlicki under Polskie blogi IT, Twórczość

CodeFirst Migrations added new extension method to DbSet<TEntity> “AddOrUpdate”. Unfortunatly this method is useles if you using identity key with identity auto increment.

I created AddOrUpdateByProperty method which solve this bug and allows You to specify property from comparision:

public static class DbSet
{
    public static void AddOrUpdateByProperty<TEntity>(this DbSet<TEntity> dbSet,
        string propertyName, params TEntity[] entities) where TEntity : class
    {
        foreach (dynamic entity in entities)
        {
            var propertyValue = typeof (TEntity).GetProperty(propertyName)
                                                .GetValue(entity, null) as object;
            var oldEntity = dbSet.AddEqualityCondition(propertyName, propertyValue).FirstOrDefault();
            if (oldEntity != null)
            { //Update

            }
            else
            { //Add
                dbSet.Add(entity as TEntity);
            }
        }
    }

    public static IQueryable<T> AddEqualityCondition<T, V>(this IQueryable<T> queryable,
        string propertyName, V propertyValue)
    {
        ParameterExpression pe = Expression.Parameter(typeof(T), "p");

        IQueryable<T> x = queryable.Where<T>(
            Expression.Lambda<Func<T, bool>>(
                Expression.Equal(Expression.Property(pe, typeof(T).GetProperty(propertyName)),
                                    Expression.Constant(propertyValue, typeof(V)),
                                    false,
                                    typeof(T).GetMethod("op_Equality")),
                new ParameterExpression[] { pe }));
        return (x);
    }
}

Hope You will find it useful :)

Web scraper, Czyli jak zautomatyzować Internet.–Przygotowanie

2012-03-15 Posted by Mateusz Świetlicki under Polskie blogi IT, Twórczość

Aby rozpocząć prace nad stworzeniem web scrapera potrzebne będzie nam seria narzędzi:

  • Fiddler – Potężne narzędzie do podsłuchu pakietów http.
  • Internet Explorer 9 i jego “F12 developers tools” – narzędzie do analizy struktury htmla oraz JavaScriptu (Oczywiście nada się też Chrome czy firefox z firebugiem)
  • Visual Studio 2010 Express lub VS 11 Beta – Środowisko programistyczne.

Wszystkie przykłady będę pisałem w języku C# 4.5 Beta chociaż większość zadziała także w C# 4.0.

OK, Gdy mamy już przygotowane środowisko jedyne co potrzebujemy to rozpoznanie celu dla naszego scrapera. Ja lubię zacząć od wypisanie adresów stron które mnie interesując oraz struktury formularzy które umożliwią mi wysyłanie informacji do portalu.

Adresy kopiujemy z pola adresu przeglądarki przeglądają portal:

http://www.codeguru.pl/kalendarium

https://www.codeguru.pl/logowanie

http://www.codeguru.pl/kalendarium/z-twoich-grup#eventTabs

http://www.codeguru.pl/kalendarium/podglad-wydarzenia/wprowadzenie-do-wcf,6354

http://tools.codeguru.pl/Logon.aspx

http://tools.codeguru.pl/system/lista-grup

http://tools.codeguru.pl/system/edycja-grupy/67

http://tools.codeguru.pl/system/edycja-grupy/Events/67

http://tools.codeguru.pl/system/edycja-grupy/Members/67

http://tools.codeguru.pl/system/edycja-grupy/67/edycja-wydarzenia/Info/6354

http://tools.codeguru.pl/system/edycja-grupy/67/edycja-wydarzenia/Users/6354

Następnie potrzebuje szablonów formularzy. Najłatwiej pobrać je Fiddlerem o ile możemy zmusić stronę do działa w http nie w https. Jeśli formularz wymusza https jego strukturę musimy wyczytać ręcznie z htmla strony.

I tak np. formularz logowania do http://tools.codeguru.pl/Logon.aspx odczytany fiddlerem wymaga następujących pól:

__EVENTTARGET
__EVENTARGUMENT
__VIEWSTATE
__EVENTVALIDATION
ctl00$cphMain$txtUserLogin
ctl00$cphMain$txtUserPassword
ctl00$cphMain$btnUserLogin

Po uruchomieniu fiddlera i upewnienia się że tryb przechwytywania jest uruchomionym, wchodzimy na stronę logowania, logujemy się, znajdujemy na liście fiddlera drugie (powrotne) odwołanie do “tools.codeguru.pl /Logon.aspx”.

70	302	HTTP	tools.codeguru.pl	/Logon.aspx	7 435	private, no-cache="Set-Cookie"  	text/html; charset=utf-8	iexplore:3480			

Następnie po prawej wybieramy zakładkę Inspectors/WebForms i odczytuje Body formularza.

Ciąg dalszy nastąpi…

Jak zrobić Web scraper? Czyli jak zautomatyzować Internet.–Wstęp

2012-03-12 Posted by Mateusz Świetlicki under Polskie blogi IT, Twórczość

Myślę, że będzie to seria artykułów opisująca jak zrobić pasywny i aktywny web scraper, czyli aplikację która ściąga dane ze stron internetowych udając człowieka.

Aplikacje tego typu są bardzo przydatne gdy chcemy rozwinąć możliwości stron internetowych, przeanalizować ich zawartość, stworzyć własne bazy danych czy automatyzować pewne procesy np.: dodawanie artykułu w wielu miejscach jednym kliknięciem.

Web scraping jest konieczny ponieważ większość stron internetowych nie udostępnia API programistycznego chociaż są wyjątki np.: Facebook, twitter, LastFM mają swoje API które są zazwyczaj wystarczające, choć facebookowe na przykład jest trochę ograniczone.

Przez kolejne artykuły przejdziemy przez proces stworzenia naszego własnego API do portalu CodeGuru.pl

Portal z powodów finansowych nie ma żadnego poprawnego interfejsu programistycznego. Co swoją stroną jest głupie bo przecież nie jest to takie pracochłonne, a przynosi spore ułatwienia dla zaawansowanych użytkowników. W powodów praktycznych tworząc API skupimy się wydarzeniach oraz administracji grupy. Pomoże to grupom .NET w całej Polsce.

OK, To tyle słowem wstępu.
Spodziewajcie się kolejnych artykułów w niedalekiej przyszłości.

Połączenie pulpitu zdalnego (RDC) – Zapamiętaj hasło

2012-03-12 Posted by Mateusz Świetlicki under Polskie blogi IT

Dziś ostatecznie zdenerwowała mnie konieczność wpisywanie hasła podczas logowania przez RDC do komputerów w tej samej domenie.

Problem leży po stronie komputera z którego próbujesz się połączyć. Domyślnie system nie chce automatycznie przekazywać poświadczeń z powodów bezpieczeństwa.

O to rozwiązanie:

  1. Otwórz  Local Group Editor (gpedit.msc).
  2. Przejdź do ścieżki Local Computer Policy –> Computer Configuration –> Administrative Templates –> System –> Credentials Delegation
  3. Otwórz “Allow Delegating Saved Credentials with NTLM-only Server Authentication”
  4. Przełącz RadioButtona na” Enabled”.
  5. Na liście serwerów poniżej (Przycisk “Show”) wpisz wszystkie swoje serwery lub “TERMSRV/*” by zezwolić wszystkie.
  6. Zapisz
  7. To samo wykonaj dla:
          Allow Delegating Saved Credentials
          Allow Delegating Default Credentials with NTLM-only Server Authentication
          Allow Delegating Default Credentials
  8. Odpal “gpupdate /force” aby zaktualizować Polityki.
SavePass

Źródło: http://naveensnayak.wordpress.com/2011/08/17/windows-7-remote-desktop-connection-save-credentials-not-working/

SharePoint i błąd “Lista nie istnieje.”

2012-02-13 Posted by Mateusz Świetlicki under Polskie blogi IT

Sharepoint 2010 często lubi wyrzucać błędy które nic człowiekowi nie mówią. Dobrym przykładem jest na przykład ten: “Lista nie istnieje."

Wybrana strona zawiera nieistniejącą listę. Mogła zostać usunięta przez innego użytkownika.<nativehr>0×81020026</nativehr><nativestack></nativestack>

Błąd ten pojawiał mi się bardzo tajemniczo zawsze tylko na 1 komputerze w firmie lub czasem w na innych w losowych przeglądarkach jak np.: firefox czy opera.

Okazuje się, że najczęstszym powodem jest błędne ustawienie mapowania dostępu alternatywnego lub brak miejsca w bazie danych.

W moim konkretnym przypadku okazało się, że użytkownik próbował logować się sharepoint wpisując adres z prefiksem “www” co powodowało problem.

Przykład:

Mapowanie było ustawione na http://naszsharepoint.pl użytkownik wpisywał http://www.naszsharepoint.pl, strona działała poprawnie ale siała dziwnymi błędami przy próbie dodania elementu do listy.

Rozwiązaniem było oczywiście poprawienie użytkownika, że adresem jest bez www z przodu i dodaniem w Centrum Administracyjnym SharePoint http://localhost:14694/_admin/AlternateUrlCollections.aspx mapowania także na adres z www. (Link działa tylko na komputerze z zainstalowanym Sharepoint 2010 dodatkowo wasz port może być inny)

PS. Swoją drogą nie rozumiem tego nawyku ludzi do wpisywania www przed nazwami stron. Myślę, że jest do niepotrzebne i mylne.

Double question mark “??” w C#

2012-02-11 Posted by Mateusz Świetlicki under Polskie blogi IT

Nie dawno natrafiłem na bardzo fajny operator w C#: podwójny znak zapytania “??”. :)

static object DoubleQuestionMarkExample1(object a, object b)
{
    return a ?? b;
}

Okazuje się, że można w ten sposób zwrócić A jeżeli A nie jest null lub zwrócić B jeżeli A jest nullem.

Na tym się jednak zabawa nie kończy, możemy zrobić tak:

static object DoubleQuestionMarkExample2(object a)
{
    return a ?? new object();
}

Lub nawet:

static object DoubleQuestionMarkExample3(object a)
{
    return a ?? (a = new object());
}

Przykład 3 aż się prosi o wykorzystanie przy tworzeniu singletonów:

private static object _a;
public static object A
{
    get { return _a ?? (_a = new object()); }
}

Tym sposobem jedną linijką zwrócimy _a jeżeli nie jest nullem, a w przeciwnym wypadku stworzymy nową instancję klasy, przypiszemy ją do _a i zwrócimy jako wartość A.

Dodatkowo fajnym faktem jest możliwość łączenia podwójnych znaków zapytania w łańcuch:

static object DoubleQuestionMarkExample4(object a, object b, object c, object d)
{
    return a ?? b ?? c ?? d;
}

Po więcej informacji polecam wątek na stackoverflow http://stackoverflow.com/questions/446835/what-do-two-question-marks-together-mean-in-c

Porządki

2012-02-11 Posted by Mateusz Świetlicki under Polskie blogi IT

Wreszcie wziąłem się za posprzątanie mojego bloga.

Poprawiłem kolorowanie kodu, powyłączałem niepotrzebne dodatki, wyczyściłem trochę interface.

Mam nadzieje, że uczyniło to Blog bardziej czytelnym.

Dynamiczne dodawanie warunków do IQueryable

2012-02-11 Posted by Mateusz Świetlicki under Polskie blogi IT

Mieliście kiedyś potrzebę stworzenia generycznej metody która enkapsulowałaby warunek LINQ i która można by użyć w zapytaniu np. do EntityFramework bez utraty IQueryable na IEnumarable?

Ja tak. Na w zapytaniu:

var sessionId = getUserSession();
var sds = DB.UserDetails.Where(d => d.SessionId == sessionId)
		    .Where(d => d.UserId == competencyScore.EnityId)
                    .Select(d => d.OfficeUnit).First();

Sprawdzenie czy detale są z danej sesji wymaga dodatkowej zmiennej i warunku, a biorąc pod uwagę, że taki sam warunek przynależności do sesji używam w wielu innych zapytaniach przydało by się go opakować w funkcję, tak aby powstało coś takiego:


var units = DB.UserDetails.InUserSession().Where(d => d.UserId == competencyScore.EnityId)
	.Select(d => d.OfficeUnit)

Jest to bardziej skomplikowane niż się wydaje ponieważ funkcja powinna być generyczna i najlepiej by rozszerzała IQuerable.

Ostatecznie udało mi się rozwiązać problem używając klasy Expression:


public static IQueryable InUserSession(this IQueryable queryable)
{
    var sessionId = getUserSession();
    return queryable.AddEqualityCondition("SessionId", sessionId);
}

public static IQueryable AddEqualityCondition(this IQueryable queryable,
                                               string propertyName, V propertyValue)
{
    ParameterExpression pe = Expression.Parameter(typeof(T), "p");

    IQueryable x = queryable.Where(
        Expression.Lambda>(
            Expression.Equal(Expression.Property(pe, typeof (T).GetProperty(propertyName)),
                             Expression.Constant(propertyValue, typeof (V)), false,
                             typeof (T).GetMethod("op_Equality")), new ParameterExpression[] {pe}));
    return (x);
}

Uwaga: AddEqualityCondition nie potrafi porównać typu prostego i jego Nullable więc wracajcie na to uwagę.

Jak uruchomić ASP.NET 4.0 po Windows 2003 IIS6

2011-09-15 Posted by Mateusz Świetlicki under Polskie blogi IT

Jeśli otrzymujecie błąd:


     
         
     


fails with
Exception information:
Exception type: ConfigurationErrorsException Exception message:
Unrecognized attribute 'targetFramework'.
Note that attribute names are case-sensitive.

To powinieneś zainstalować .NET 4.0 framework oraz uruchomić na serwerze:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis -i>

Jako ciekawostkę dodam, że ASP.NET 4.0 można wyinstalować komendą:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis -u     

Exchange 2010 – The WinRM client received an HTTP server error status (500)

2011-09-13 Posted by Mateusz Świetlicki under Polskie blogi IT

exchange2010

Natknąłem się ostatnio znów na problem z serwerem Exchange 2010 stojącym na wirtualnym WS2008R2. Przy próbie połączenia z konsolą exchange wyświetlał się komunikat błędu:

Connecting to remote server failed with the following error message : The WinRM client received an HTTP server error status (500), but the remote service did not include any other information about the cause of the failure. For more information, see the about_Remote_Troubleshooting Help topic.

Rozwiązanie okazuje się dość proste, wystarczy wywołać 2 komendy PowerShella:

Import-Module ServerManager
Add-WindowsFeature WinRM-IIS-Ext

Które zainstalują WinRM IIS Extensions.

Problem czasu przy wsHttpBinding

2011-07-15 Posted by Mateusz Świetlicki under Polskie blogi IT

Inner Exception: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.

Problem w moim przypadku wystąpił przy próbie połączenia proxy z usługą WCF korzystającej z wsHttpBinding, ponieważ godzina serwera różniła się o około 10min od godziny klienta. Co ciekawe to serwer miał zły czas.

Windows Serwer 2008 R2 PortMapping

2011-07-11 Posted by Mateusz Świetlicki under Polskie blogi IT
netsh routing ip nat add portmapping external tcp 0.0.0.0 5555 192.168.0.2 3389
netsh routing ip nat show interface

EWS i HTTP status 401: Unauthorized.

2011-07-08 Posted by Mateusz Świetlicki under Polskie blogi IT

Cześć,

Natknąłem się ostatnio na problem podłączenia się do Exchange 2010 SP1, wykorzystując EWS (Exchange Web Service)

Podczas próby połączenia się do usługi serwer zwracał błąd: “The request failed with HTTP status 401: Unauthorized.” lub cos o niedostępności Active Directory.
Problem dziwny ponieważ dane logowania na pewno podawałem poprawne.

Mój kod wyglądał w ten sposób:

ExchangeService service =
 new ExchangeService(ExchangeVersion.Exchange2010_SP1);
service.Credentials = new WebCredentials("temp1", "temp", "domena");
service.TraceEnabled = true;
service.Url = new Uri("http://192.168.0.205/EWS/Exchange.asmx");

ListAppointments(service);

Po przejrzeniu wielu niepomocnych wątków w Internecie spróbowałem przejrzeć się samej klasie ExchangeService gdzie znalazłem:

service.PreAuthenticate = true;

Co natychmiastowo rozwiązało mój problem.

Mam nadzieję, że wam też rozwiązanie pomoże.

Problem z reinstalacją aplikacji ClickOnce

2011-04-11 Posted by Mateusz Świetlicki under Polskie blogi IT

Czyszczenie cacha w wypadku problemu z już zinstalowaną aplikacją:

rundll32 dfshim CleanOnlineAppCache

Problemy z instalacją Exchange 2010

2011-03-11 Posted by Mateusz Świetlicki under Polskie blogi IT

imageCześć,

Opisze dzisiaj serię problemów które miałem z instalacją Microsoft Exchange 2010 SP1 pod Windows Server 2008 R2 SP1 i migrację danych z Exchange 2003 działającym na Windows Server 2003 R2 SP2 PL który jest również kontrolerem domeny poziomu Windows Server 2003 Native.

OK, oto lista błędów  w chronologicznej kolejności:

  1. "Active Directory does not exist”. OK, upewniłem się że DNS jest poprawnie ustawiony na serwer AD, a nie na internet, oczywiście był bo było to konieczne do dodatnia serwera do domeny. Następnie po chwili googlowania with bing pomógł msdn http://technet.microsoft.com/en-us/library/bb125224.aspx i komenda “ServerManagerCmd -i RSAT-ADDS” uruchomiona na komputerze pod Exchange 2010.
  2. “The schema master is not running Windows Server 2003 Service Pack 1”. Tutaj okazało się, że problemem jest polska wersja windowsa. Należało zmienić ustawienia na serwerze domeny przy użyciu ADSI Edit (AdsiEdit.msc). Okazało się że kontroler domeny przedstawiał swój operationSystemServicePack jako “Dodatek Service Pack 2” zamiast “Service Pack 2”.
    image
  3. Dalej jeszcze gorzej. Tym razem “Could not find any Domain Controller in domain 3w.local.”. Póki co uruchomiłem “PS D:\> .\Setup.com /PrepareAD” gdzie d: jest dyskiem instalacyjnym exchange 2010 i czekam dobrą godzinę na zakończenie. OK, Super zakończyło się bez błędu, uruchomiłem jeszcze “PS D:\> .\setup.com /PrepareDomain” dla pewności i wystartowałem okienkową instalację.
    image
    image
  4. Hmm, znowu “The schema master is not running Windows Server 2003 Service Pack 1” powtórzę stare rozwiązanie z AdsiEdit.msc…
  5. Super, jeszcze tylko Warningi:
    1. ”This computer requires the Microsoft Office 2010 Filter Packs.” Szybki skok na http://go.microsoft.com/fwlink/?LinkID=191548 i po problemie.
    2. ”If Microsoft Outlook 2003 is in use, you should replicate the free/busy folder on this server to every other free/busy server in the organization. This step should be performed once Setup completes.” ale to później.
  6. 27min i instalacja zakończyła się sukcesem. Updates i Restart.
  7. Przenoszenie danych:
  • Problem z certyfikatem SSL. Jeszcze nie rozwiązany…

  • dbml

    2010-08-15 Posted by Mateusz Świetlicki under Polskie blogi IT

    Create a .dbml descriptor file for the Database
    To do this you need to use the SqlMetal.exe tool. Just type the following into the Visual Studio 2008 Command Prompt:
    SqlMetal.exe MyDatabase.sdf /dbml:MyDatabase.dbml
    By default, the SqlMetal.exe is located at drive:\Progream Files\Microsoft SDKs\Windows\vn.nn\bin

    SharePoint 2010 i PowerShell użyteczne skrypty

    2010-08-02 Posted by Mateusz Świetlicki under Polskie blogi IT
    W nowym SharePoint 2010 sryptowe zarządzanie zostało przeniesione z STSADM
    do coraz popularniejszego PowerShella.
    W tym artykulę napiszę postaram się zamieścić podstatowe użyteczne skrypty dla developera SP2010.
    By zacząć pracę z SharePoint 2010 w consoli PowerShell należy uruchomić wersję x64 konsoli i zainportować polecenia:
    Add-PSSnapin Microsoft.SharePoint.PowerShell
    Teraz można już przetestować działanie enumerując kontrolki:
    Get-SPFarm
    Oczywiście jeżeli nie chcesz wpisywać tego za każdym razem gdy chcesz się dostać do SP możesz dodać powyższą komendę do pliku (który domyślnie nie istnieje):
    <user_documents>/WindowsPowerShell/Microsoft.PowerShell_profile.ps1
     
    Przykłądowy skrypt wysukujący content typów danej listy i tworzący elementy na innej liście
    $12HivesDir = "${env:CommonProgramFiles}\Microsoft Shared\web server extensions\14\"
    [System.Reflection.Assembly]::LoadFrom("$12HivesDir\ISAPI\Microsoft.SharePoint.dll")
    
    $devSite = New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "http://192.168.0.201/Repozytorium";
    $devWeb = $devSite.OpenWeb();
    
    $zadania = $devweb.GetList(“http://192.168.0.201/Repozytorium/Lists/Zadania")</a>
    
    $types = @()
    $dtypes = @()
    foreach($ctype in $zadania.ContentTypes)
    {
    $types += $ctype.name
    }
    
    $opisy = $devweb.GetList(http://192.168.0.201/Repozytorium/Lists/Opisy%20wiadomoci)
    
    foreach($ctype in $opisy.items)
    {
    $dtypes += $ctype.name
    }
    
    foreach($ctype in $types)
    {
    if($dtypes -notcontains $ctype)
    {
    Write-Host "Dodaje element: ", $ctype
    $item = $opisy.AddItem()
    $item.item("Typ zadania") = $ctype
    $item.Update()
    }
    }
     
     
    Ciąg dalszy nastąpi…

    Problemy po instalacji SharePoint 2010

    2010-08-02 Posted by Mateusz Świetlicki under Polskie blogi IT

    Pracując ostatnio w małej firmie programistycznej natkneliśmy się na pożny problem podczas naszych pierszych kroków z SharePoint 2010.

    Po instalacji SharePointFundation wszystko zdawało się działać dobrze dla osoby która go zainstalowała, ale gdy ktoś próbował dostać się z zewnątrz czy nawet później z serwera nagle wszystko działało dziwnie.

    Otóż:

    • listy działały tak jakby tylko na stronie głównej
    • panele administracyjne dodanych fitryn wyrzucały błędy braku pliku
    • system nie widział użytkowników domeny

    Męczyliśmi się z tym kilka dobrych godzin myśląc że to błąd instalacji SP czy specyfikacji serwera. Na koniec jednak okazało się że błąd jest banalny.

    Błędy tego typu występują gdy użytkownik próbuje dostać się do serwera podając adres który nie jest skonfigurowany w ustawieniach mapowania alternatywnego.

    Jeżeli np. mapowanie jest skonfigurowane na http://mojserwer to dostanie się z http://localhost czy http://192.168.0.1 mimo że teoretycznie poprawne powoduje błędy linków i tym samym w.w. problemy.

    Należy więc dodać wszystkie możliwe mapowania do konfiguracji w paneli administracyjnym.

    Archiwa
    • Maj 2012 (68)
    • Kwiecień 2012 (159)
    • Marzec 2012 (196)
    • Luty 2012 (153)
    • Styczeń 2012 (128)
    • Grudzień 2011 (101)
    • Listopad 2011 (80)
    • Październik 2011 (94)
    • Wrzesień 2011 (49)
    • Sierpień 2011 (30)
    • Lipiec 2011 (21)
    • Czerwiec 2011 (14)
    • Maj 2011 (21)
    • Kwiecień 2011 (32)
    • Marzec 2011 (14)
    • Luty 2011 (13)
    • Styczeń 2011 (29)
    • Grudzień 2010 (11)
    • Listopad 2010 (22)
    • Październik 2010 (19)
    • Wrzesień 2010 (19)
    • Sierpień 2010 (15)
    • Lipiec 2010 (9)
    • Czerwiec 2010 (5)
    • Maj 2010 (5)
    • Kwiecień 2010 (13)
    • Marzec 2010 (13)
    • Luty 2010 (20)
    • Styczeń 2010 (13)
    • Grudzień 2009 (16)
    • Listopad 2009 (19)
    • Październik 2009 (30)
    • Wrzesień 2009 (14)
    • Sierpień 2009 (11)
    • Lipiec 2009 (25)
    • Czerwiec 2009 (2)
    • Maj 2009 (12)
    • Kwiecień 2009 (9)
    • Marzec 2009 (5)
    • Luty 2009 (5)
    • Styczeń 2009 (6)
    • Grudzień 2008 (6)
    • Listopad 2008 (4)
    • Październik 2008 (6)
    • Wrzesień 2008 (3)
    • Kwiecień 2008 (1)
    • Grudzień 2007 (1)
    Kategorie
    2003 2010 access Access 2003 Access 2010 Aktualności Bez kategorii BI CTP exchange online Exchange Server Exchange Server 2010 featured funkcje Grzegorz Tworek How To Hyper-V 3 Hyper-V Server 8 interoperacyjność IT Pro blogerzy Jak to zrobić Komputery i Internet Microsoft Outlook najlepsze praktyki Narzędzia open source Oprogramowanie PLSSUG Polskie blogi IT Porady PowerPivot Relacje Reporting Services SharePoint Foundation 2010 SharePoint Server 2010 Skrypty System Center 2012 Techniczne Tips and tricks video Virtual Machine Manager wersje beta WGUiSW Windows 8 Beta Windows 8 Customer Preview
    Tagi
    .net Active Directory Artykuły Blog blogosfera Cloud Computers and Internet CRM 2011 Excel Exchange Exchange 2010 Hyper-V Inne IT konferencja Konferencje Linux Lync Microsoft Microsoft Dynamics CRM News office 365 Ogólne PowerShell Private Cloud programowanie Publikacje Security SharePoint Społeczności IT SQL SQL Server SQL Server 2012 System Center Uncategorized Windows Windows 7 Windows 8 Windows Phone 7 Windows Server Windows Server 8 Windows Server 2008 Wirtualizacja Wydarzenia [EN]
    Autorzy
    Kamil Skalski, Konrad Sagala, Szymon Bochniak, Tadeusz , Tomasz Filipowicz, RSS , Łukasz Kałużny, kgorczewski , Łukasz , Wojciech Gardziński, Paweł Goleń, Dariusz Porowski, Piotrek Gardy, koprowskit , nExoR , Joanna Subik, Mateusz Świetlicki, Marcin , piotrpawlik , TechNet Polska, gsgalezowski , T4ngram , Metorio , Maciek Blog, Bloggers Underground, blog Michała Cywińskiego..., Me & Technology – Paula’s Security Blog, swilczew , pawp81 , programistaaccess , Bartek Bielawski, soisk , Zygmunt B., MS Dynamics Blog, Jarek Szybiński, rtynski , Filip , Świat Office, voytas , jaroslawsokolnicki , rem8 , Łukasz Matuszewski, Seb , kaarol , Peter , Kamil Karczmarczyk, Dariusz Brejnak, JeZZoo , bns , Pawel Potasinski, Kuba Skałbania, t.onyszko , robertmandziarz , Krzysiek , MKr , szulcu , Robert Stuczynski - Noise, kicekpicek , Dobert , Łukasz Zięba, drixter , Maciej Krasuski, Tomasz_Sochacki , Przemek Kuczyński, losiak , paramo , OSKAr , SzymonN , Marcin Milewski, marcinbojko , l10n , Łukasz Z., Grzesiek Bartosik, jnx
    Polskie blogi specjalistów IT / Microsoft powered by WordPress and The Clear Line Theme