BLOGas.lt
Sukurk savo BLOGą Kitas atsitiktinis BLOGas

IIS7 klaida "HTTP Error 500.19 - Internal Server Error"

Parašė Sergejus | 2010-12-29 21:56

Darbe kolegos susidūrė su įdomia IIS 7 problema, kuri pasireiškė tam tikruose Windows Server 2008 serveriuose. Sudiegus ASP.NET MVC 2 aplikaciją ir bandant ją pakrauti – įvykdavo IIS klaida „HTTP Error 500.19 - Internal Server Error“.

Module: IIS Web Core

Notification: BeginRequest

Handler: Not yet determined

Error Code: 0×80070021

Config Error This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".

Sprendimas (net keli) pasirodo yra paprastas, bet pakankamai sunkiai surandamas. Klaidos priežastis – nauja IIS 7 galimybė Feature Delegation, kuri leidžia uždrausti keisti tam tikrus IIS nustatymus, kaip, pavyzdžiui, pridėti naujus modulius (angl. modules). Šiuo atveju, reikėjo leisti keisti modules ir handlers nustatymus iš aplikacijos Web.config failo.

Sprendimo būdas #1 (iš IIS Manager)

IIS Manager lange pasirinkite Feature Delegation punktą:

image

Suraskite punktą Modules ir iš kontekstinio meniu pasirinkite Read/Write:

image

Pakartokite tą pati su Handlers.

Sprendimo būdas #2 (iš komandinės eilutės)

Įvykdykite žemiau pateiktas komandas iš komandinės eilutės (administratoriaus teisėmis):

%windir%\system32\inetsrv\appcmd.exe unlock config /section:system.webServer/handlers

%windir%\system32\inetsrv\appcmd.exe unlock config /section:system.webServer/modules

Sprendimo būdas #3 (iš konfigūracijos failo)

Atidarykite globalų IIS konfigūracijos failą %windir%\system32\inetsrv\config\applicationHost.config. Jame suraskite sekciją modules:

<section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />

Pakeiskite į overrideModeDefault="Allow".

Pakartokite tą pati su handlers ir išsaugokite pakeitimus.

 

Tikiuosi šis straipsnis ateityje išsaugos jums laiką ieškant šios problemos sprendimo būdų.

Rodyk draugams

FTP over SSL konfigūravimas IIS 7 ir jo panaudojimas iš C#

Parašė Sergejus | 2010-12-27 21:24

FTP yra vienas iš seniausių failų mainų protokolų, kuriam Microsoft, mano manymu, skyrė neypatingą dėmesį. Apart tradicinio, nesaugaus FTP protokolo, egzistuoja dvi jo variacijos: FTP over SSH, dar žinomas kaip Secured FTP arba SFTP bei FTP over SSL, dar žinomas kaip FTPS. Iki šiol nei viena, nei kita saugaus FTP atmaina nebuvo oficialiai palaikoma IIS, todėl tekdavo naudoti trečios šalies FTP serverius. Laimei, atsirado galimybė parsisiųsti FTP Publishing Service, skirtą IIS 7 ir naujesnėms versijoms.

Konfigūravimas

Suinstaliavus FTP Publishing Service, IIS Manager atsiras nauji su FTP susiję punktai:

image

Prieš pradedant konfigūruoti FTP over SSL, pirma reikia sugeneruoti SSL sertifikatą, tai galima padaryti paspaudus ant Server Certificates ir pasirinkus punktą Create Self-Signed Certificate:

image

Norėdami pridėti naują FTPS saitą, užtenka paspausti dešiniu pelės mygtuku ant katalogo Sites ir pasirinkti Add Ftp Site. Atsiradusiame lange įvedame FTP pavadinimą bei fizinį adresą. Kitame vedlio žingsnyje reikalaujame SSL panaudojimą bei nurodome prieš tai sugeneruotą sertifikatą:

image

Paskutiniame dialogo lange nurodome kas galės prieiti prie mūsų FTP, mano atveju, specialiai sukurtas vartotojas ftpuser:

image

Štai ir viskas, tai yra minimaliai reikalinga FTP over SSL konfigūracija skirta IIS 7.

FTPS panaudojimas

Žemiau pateiktas kodo pavyzdys, parodantys kaip prisijungti prie FTP over SSL:

static void Main(string[] args)
{
    ServicePointManager.ServerCertificateValidationCallback =
        (sender, certificate, chain, sllPolicyErrors) => true; 

    const string url = "ftp://localhost/";
    var ftp = (FtpWebRequest)WebRequest.Create(url);
    ftp.Credentials = new NetworkCredential("ftpuser", "ftp");
    ftp.UsePassive = true;
    ftp.EnableSsl = true;
    ftp.Method = WebRequestMethods.Ftp.ListDirectory;
    var response = (FtpWebResponse)ftp.GetResponse();

    using(var reader = new StreamReader(response.GetResponseStream()))
    {
        Console.WriteLine(reader.ReadToEnd());
    }

    Console.ReadKey();
}

Atkreipkite dėmesį į delegatą ServicePointManager.ServerCertificateValidationCallback. Kadangi aš naudoju taip vadinamą Self-Signed sertifikatą, įprastas FtpWebRequest išmestų su sertifikatu susijusią klaidą. Vienas iš apėjimo variantų – nurodyti sertifikato tikrinimo delegatą, kuris tiesiog visada grąžina true.

Tikiuosi šis straipsnis padės jums greičiau sukonfigūruoti bei pasinaudoti FTP over SSL.

Rodyk draugams

Pingy - #8 PingReportItem ir PingReportRepository

Parašė Sergejus | 2010-12-22 23:06

Primenu, Pingy – tai mano bandymas sukurti paslaugą, kuri kas tam tikrą laiką kreiptųsi į vartotojo nurodytą URL, taip neduodant IIS užmigti. Tuo pačiu metu bus renkama statistika apie serverio būseną, atsakos laikas ir pan. Pingy yra kuriamas specialiai Windows Azure mokymosi tikslais.

Turinys

Pingy - #1 Architektūra
Pingy - #2 Windows Azure Table ir NoSQL mąstymas
Pingy - #3 PingItem ir PingItemRepository
Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod
Pingy - #5 Windows Azure Queue ir PingTaskRepository
Pingy - #6 Windows Azure Queue korektiškas žinučių apdorojimas
Pingy - #7 Pinger serviso kūrimas
Pingy - #8 PingReportItem ir PingReportRepository

Praeitoje dalyje mes sukūrėme Pinger servisą, kuris atlieka pagrindinę Pingy aplikacijos logiką – kreipiasi į nurodytus URL ir tikrina, ar serveris yra pasiekiamas. Šio kreipimosi rezultatas buvo talpinamas į PingReportRepository repozitoriją, kurią mes šioje dalyje ir įgyvendinsime.

PingReport esybės

Kaip ir PingItem atveju, pirma aprašysime modelį PingReportItem:

public class PingReportItem
{
    public string Client { get; set; }
    public string Url { get; set; }
    public DateTime CollectedOn { get; set; }
    public int StatusCode { get; set; }
    public TimeSpan ResponseTime { get; set; }
}

StatusCode – tai HTTP atsakymo kodas, o ResponseTime – laiko intervalas, per kiek mes gavome atsakymą iš serverio. Kadangi saugojimui naudosime Windows Azure Table Storage, pagal analogiją su PingItem būtina aprašyti esybę PingReportEntity:

public class PingReportEntity : TableServiceEntity
{
    public string Url { get; set; }
    public DateTime CollectedOn { get; set; }
    public int StatusCode { get; set; }
    public long ResponseTime { get; set; }
}

Atkreipkite dėmesį, kad šioje esybėje kliento pavadinimas bus naudojamas kaip PartitionKey, o RowKey bus sudarytas iš trejeto Client, Url ir CollectedOn. Paprastesniam darbui su PingReportItem ir PingReportEntity aprašykime konverterį:

public static class PingReportConverter
{
    public static PingReportItem ToPingReportItem(this PingReportEntity entity)
    {
        return new PingReportItem
        {
            Client = entity.PartitionKey,
            Url = entity.Url,
            CollectedOn = entity.CollectedOn,
            StatusCode = entity.StatusCode,
            ResponseTime = TimeSpan.FromMilliseconds(entity.ResponseTime)
        };
    }

    public static PingReportEntity ToPingReportEntity(this PingReportItem reportItem)
    {
        return new PingReportEntity
        {
            PartitionKey = reportItem.Client,
            RowKey = String.Format("{0}_{1}_{2}", reportItem.Client, reportItem.Url.SanitizeUrl(),
                                                  reportItem.CollectedOn.ToFileTimeUtc()),
            Url = reportItem.Url,
            CollectedOn = reportItem.CollectedOn,
            StatusCode = reportItem.StatusCode,
            ResponseTime = (long)reportItem.ResponseTime.TotalMilliseconds
        };
    }
}

PingReportRepository įgyvendinimas

PingReportRepository realizacija labai panaši į PingItemRepository:

public class PingReportRepository : IPingReportRepository
{
    private readonly CloudStorageAccount account;
    private readonly string pingReportEntityTable = typeof(PingReportEntity).Name;

    public PingReportRepository(CloudStorageAccount account)
    {
        this.account = account;

        var client = account.CreateCloudTableClient();
        client.CreateTableIfNotExist(pingReportEntityTable);
    }

    public IEnumerable<PingReportItem> GetClientReportItems(string client)
    {
        return CreateContext().CreateQuery<PingReportEntity>(pingReportEntityTable)
                              .Where(e => e.PartitionKey == client)
                              .AsTableServiceQuery()
                              .Execute()
                              .Select(e => e.ToPingReportItem());
    }

    public void AddReportItem(PingReportItem item)
    {
        var context = CreateContext();

        var pingReportEntity = item.ToPingReportEntity();
        context.AddObject(pingReportEntityTable, pingReportEntity);
        context.SaveChanges();
    }

    public void RemoveClientReportItems(string client)
    {
        var context = CreateContext();

        var entities = context.CreateQuery<PingReportEntity>(pingReportEntityTable)
                              .Where(e => e.PartitionKey == client)
                              .AsTableServiceQuery()
                              .Execute()
                              .ToList();

        foreach (var entity in entities)
        {
            context.DeleteObject(entity);
        }
        context.SaveChanges();
    }

    protected TableServiceContext CreateContext()
    {
        return new TableServiceContext(account.TableEndpoint.ToString(), account.Credentials);
    }
}

Kitoje dalyje…

Šioje dalyje mes aprašėme paskutinę pirmai iteracijai reikalingą repozitoriją PingReportRepoository ir su ja susijusias klases. Kitoje dalyje įgyvendinsime dar vieną Worker rolę – PingScheduler, atsakingą už kreipimosi į nurodytus URL užduočių sukūrimą bei valdymą.

Rodyk draugams

Kinect - išpakavimas ir pajungimas (video)

Parašė Sergejus | 2010-12-15 08:17

Šiandien pagaliau gavau dvi savaites lauktą Kinect for XBOX360. Užsakinėjau iš Anglijos, game.co.uk puslapyje. Kaina su pristatymu gavosi 550 litų. Kinect išpakavimo ir pajungimo video įspūdžiai žemiau.

Kinect išpakavimas

 

Kinect pajungimas

Rodyk draugams

ASP.NET MVC3: Razor sintaksė

Parašė Sergejus | 2010-12-08 21:38

ASP.NET MVC3 jau ne už kalnų, o Release Candidate versiją galite parsisiųsti jau dabar. Kaip žinia, kartu su ASP.NET MVC3 atsiras ir naujasis atvaizdavimo variklis Razor. Šiame straipsnyje pabandysiu vaizdžiai paaiškinti naują Razor sintaksę, migruojant esamą ASP.NET MVC aplikaciją nuo WebForms atvaizdavimo variklio prie Razor.

Web aplikacijos struktūra

Paprastumo dėlei, aprašiau tokią minimalią ASP.NET MVC aplikaciją:

razor1

Kaip matyti, mes naudojame Layout.Master šabloninį puslapį, Person modelį bei PersonController kontrolerį. Kadangi mes keisime tik atvaizdavimo dalį – modelis ir kontroleris nesikeis ir atrodys taip:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Blog { get; set; }
    public string Twitter { get; set; }
    public IList<string> Interests { get; set; }
}
public class PersonController : Controller
{
    public ActionResult Index()
    {
        var model = new Person
        {
            FirstName = "Sergejus",
            LastName = "Barinovas",
            Blog = "sergejus.blogas.lt",
            Twitter = "sergejusb",
            Interests = new List<string>
            {
                "Windows Azure",
                "ASP.NET MVC",
                "C#",
                "Data Access"
            }
        };

        return View("Index", model);
    }

}

Perėjimas prie Razor

Norėdami pereiti prie Razor sintaksės, pakeisime Layout.Master ir Index.aspx failus į _Layout.cshtml ir Index.cshtml (c# su html).

Layout.Master

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <title>
        <asp:ContentPlaceHolder ID="Title" runat="server"/>
    </title>

    <link href='~/Content/Site.css' rel="stylesheet" type="text/css" />
    <script src='<%: Url.Content("~/Scripts/jquery-1.4.1.min.js")%>' type="text/javascript"></script>
    <%--
    <script src='<%: Url.Content("~/Scripts/jquery.validate.min.js")%>' type="text/javascript"></script>
    --%>

    <asp:ContentPlaceHolder ID="Head" runat="server" />
</head>
<body>
    <form id="Form" runat="server">
        <div id="main-container">
            <asp:ContentPlaceHolder ID="Body" runat="server" />
        </div>
        <div id="footer-container">
            <asp:ContentPlaceHolder ID="Footer" runat="server" />
        </div>
    </form>
</body>
</html>

_Layout.cshtml

<!DOCTYPE html>

<html>
<head>
    <title>@View.Title</title>

    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.1.min.js")" type="text/javascript"></script>
    @*<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>*@

    @RenderSection("Head", required: false)
</head>

<body>
    <div id="main-container">
        @RenderBody()
    </div>
    <div id="footer-container">
        @RenderSection("Footer")
    </div>
</body>
</html>

Index.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Layout.Master" Inherits="System.Web.Mvc.ViewPage<OldWeb.Models.Person>" %>

<asp:Content ContentPlaceHolderID="Title" runat="server">
    About
</asp:Content>

<asp:Content ContentPlaceHolderID="Body" runat="server">
    <h2>About</h2>
    Name: <%: Model.FirstName %>
    <br />
    Surname: <%: Model.LastName %>
    <br />
    Blog: <%: String.IsNullOrEmpty(Model.Blog) ? "N/A" : Model.Blog %>
    <br />
    Interests:
    <ul>
        <% foreach (var interest in Model.Interests) { %>
            <li><%: interest %></li>
        <% } %>
    </ul>
</asp:Content>

<asp:Content ContentPlaceHolderID="Footer" runat="server">
    SB, 2010 ©
</asp:Content>

Index.cshtml

@inherits System.Web.Mvc.WebViewPage<Web.Models.Person>
@{
    View.Title = "About";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>About</h2>
Name: @Model.FirstName
<br />
Surname: @Model.LastName
<br />
Blog: @(String.IsNullOrEmpty(Model.Blog) ? "N/A" : Model.Blog)
<br />
Interests:
<ul>
    @foreach (var interest in Model.Interests) {
    <li>@interest</li>
    }
</ul>

@section Footer {
SB, 2010 ©
}

Manau aukščiau pateiktas kodas yra pakankamai suprantamas ir detalesnio paaiškinimo nereikalauja. Naujoji sintaksė man pasirodė intuityvi, švari bei greitai išmokstama. Daugiau informacijos apie Razor sintaksę galite rasti dokumente ASP.NET Web Pages Using The Razor Syntax.

Rodyk draugams

Pingy - #7 Pinger serviso kūrimas

Parašė Sergejus | 2010-12-04 16:28

Primenu, Pingy – tai mano bandymas sukurti paslaugą, kuri kas tam tikrą laiką kreiptųsi į vartotojo nurodytą URL, taip neduodant IIS užmigti. Tuo pačiu metu bus renkama statistika apie serverio būseną, atsakos laikas ir pan. Pingy yra kuriamas specialiai Windows Azure mokymosi tikslais.

Turinys

Pingy - #1 Architektūra
Pingy - #2 Windows Azure Table ir NoSQL mąstymas
Pingy - #3 PingItem ir PingItemRepository
Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod
Pingy - #5 Windows Azure Queue ir PingTaskRepository
Pingy - #6 Windows Azure Queue korektiškas žinučių apdorojimas
Pingy - #7 Pinger serviso kūrimas
Pingy - #8 PingReportItem ir PingReportRepository

5 dalyje mes esame aprašę PingTaskRepository, o praeitoje dalyje sužinojome kaip korektiškai daryti Windows Azure Queue žinučių apdorojimą. Šioje dalyje mes tai apjungsime į vieną visumą įgyvendinant Pinger servisą.

Pinger servisas

Pinger servisas – tai Class Library tipo projektas, kuris bus vykdomas Windows Azure Worker rolėje. Kiekviena Worker rolė privalo paveldėti iš RoleEntryPoint klasės, kurioje mes aprašysime du veiksmus: OnStart in Run. Pirmajame metode turi būti aprašomi visi veiksmai, kurie turi būti atlikti vieną kartą startuojant servisui, o antrajame – serviso verslo logika. Supaprastintai, Pinger serviso WorkerRole klasė atrodys taip:

public class WorkerRole : RoleEntryPoint
{
    private const int DequeueThreadhold = 5;
    private static readonly TimeSpan SleepInterval = TimeSpan.FromSeconds(60);

    private IPingTaskRepository pingTaskRepository;
    private IPingReportRepository pingReportRepository;

    public override bool OnStart() { }

    public override void Run() { }
}

Kaip tikriausiai pastebėjote, mes naudojame dvi repozitorijas: PingTaskRepository bei PingReportRepository. Pastarosios realizaciją pateiksiu kitoje dalyje. Konstantos DequeueThreadhold ir SleepInterval bus reikalingos korektiškam žinučių apdorojimui.

Metodas OnStart

Metode OnStart mes atliekame 4 pagrindinius veiksmus:

  • Nusakome kaip reaguoti į pasikeitimus Windows Azure rolės konfigūracijoje (pasikeitimai nebus iš karto pritaikomi rolei)
  • Nurodome iš kur skaityti konfigūracijos nustatymus (iš Windows Azure projekto ServiceDefinition failo)
  • Sukuriame Windows Azure Storage Account pagal nustatymus konfigūraciniame faile
  • Sukuriame prieš tai minėtas repozitorijas
public override bool OnStart()
{
    // Are any of the environment changes a configuration setting change? 
    // If so, cancel the event and restart the role
    RoleEnvironment.Changing += (sender, e) =>
        e.Cancel = e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange);

    // Provide the configSetter with the initial value
    CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
        configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)));

    var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
    pingTaskRepository = new PingTaskRepository(account);
    pingReportRepository = new PingReportRepository(account);

    return base.OnStart();
}

Metodas Run

Metodas Run įgyvendina praeitoje dalyje aprašyta žinučių apdorojimo šabloną:

  • Verslo logiką vykdomą pastoviai (while true)
  • Bandoma gauti PingTask objektą iš repozitorijos (eilės)
  • Jeigu pavyksta – vykdomas tolesnis darbas
  • Jeigu ne (eilėje nėra nei vienos užduoties) – laukiam SleepInterval laiką
  • Galiausiai, jeigu klaidų nebuvo arba buvo aptikta kenkėjišką žinutė – ją ištriname iš repozitorijos (eilės)

Trinant žinutę gali iškilti situacija, kad ji jau buvo ištrinta – tokias situacijas tiesiog ignoruojame

public override void Run()
{
    while (true)
    {
        PingTask task = null;
        var success = false;

        try
        {
            task = pingTaskRepository.GetTask();

            if (task != null)
            {
                var request = WebRequest.Create(task.PingItem.Url);
                var stopwatch = Stopwatch.StartNew();
                using (var response = (HttpWebResponse)request.GetResponse())
                {
                    stopwatch.Stop();
                    var item = new PingReportItem
                    {
                        Client = task.PingItem.Client,
                        Url = task.PingItem.Url,
                        CollectedOn = DateTime.UtcNow,
                        StatusCode = (int)response.StatusCode,
                        ResponseTime = TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds)
                    };

                    pingReportRepository.AddReportItem(item);
                }

                success = true;
            }
            else
            {
                Thread.Sleep(SleepInterval);
            }
        }
        catch (Exception)
        {
            // TODO: Log exception
            success = false;
        }
        finally
        {
            if (success || task != null && task.DequeueCount > DequeueThreadhold)
            {
                try
                {
                    pingTaskRepository.DeleteTask(task);
                }
                catch (StorageClientException ex)
                {
                    if (ex.ExtendedErrorInformation.ErrorCode == "MessageNotFound")
                    {
                        // Pop receipt must be invalid
                        // TODO: Log, so we can tune the visibility timeout
                    }
                    else
                    {
                        // TODO: Log
                    }
                }
            }
        }
    }
}

Kitoje dalyje…

Šioje dalyje parodžiau kaip sukurti Windows Azure Worker rolę, kitoje įgyvendinsime šioje dalyje panaudotą PingReportRepository.

Rodyk draugams