Monday, November 24, 2014

DbKeeperNet - How to seed ASP.NET users and roles

Introduction

It is a common task that as a part of database setup you need to seed some default user accounts and roles into the database as a part of setup.

DbKeeperNet is an opensource .NET/C# framework which helps you manage database schema for your database performing various types of upgrade steps. DbKeeperNet is designed with support for various database types in mind. Currently it supports most common databases: MSSQL, SQLite, Firebird, MySQL, Oracle. Since the whole framework is extensible adding support of a new database type is just a simple task.

It is just matter of few minutes to get it set up in your project and have in-place infrastructure which will ensure proper upgrade path for your database schema on all installations for your application.

In its recent version DbKeeperNet also support seeding of the ASP.NET membership and roles. With respect to overall design - this is supported on any database which implemented its membership providers and makes them available to the .NET infrastructure.

Please keep in mind that any seeded account with pre-seeded password should change the seeded password ASAP.

Sample task

Let’s consider the following set of operations you would perform in your database during the time as your application evolves (of course this can be mixed with any other database schema change like adding a table):

Upgrade to version 1.00

  • If running on MSSQL setup the membership schema
  • Create role TestRole1
  • Create role TestRole2
  • Create user TestUser1 assigned to TestRole1 and TestRole2

Upgrade to version 1.01

  • Create user TestUser2 assigned to TestRole1
  • Delete user TestUser1
  • Delete TestRole2

Upgrade script

Part of this article is a console application demo project using the script below and referencing DbKeeperNet as a Nuget package:

  • The demo project is created for the MSSQL but it can be easily adopted for any other database just by changing setup in App.Config
    * The MSSQL specific step here is necessary since the DB schema creation script requires to be executed within a separated transaction and each of the steps needs to be commited
    • For example MySQL providers seed the required schema on its own upon the first usage of membership providers.
  • It can be easily adopted and used in a web application - you simply have to plan for its initial execution.

DbKeeperNet is using an XML validated against the XSD schema to define a database upgrade. Below you can find an example database upgrade script to achieve above steps (this is comming directly from the example):

<?xml version="1.0" encoding="utf-8"?>
<upd:Updates xmlns:upd="http://code.google.com/p/dbkeepernet/Updates-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" AssemblyName="DbKeeperNet.SimpleDemo" xsi:schemaLocation="http://code.google.com/p/dbkeepernet/Updates-1.0.xsd ../../DbKeeperNet.Engine/Resources/Updates-1.0.xsd">
  <!-- Default way how to check whether to execute update step or not -->
  <DefaultPreconditions>
    <!-- We will use step information saving strategy -->
    <Precondition FriendlyName="Update step executed" Precondition="StepNotExecuted"/>
  </DefaultPreconditions>
  <Update Version="1.00">
    <!--
    This update step is needed to properly inject MSSQL membership schema into the database.
    The challenge here is that the schema setup must be executed in separated transaction.

    For other membership providers this is usually handled automatically upon the first usage
    (like for MySql)
    -->
    <UpdateStep xsi:type="upd:CustomUpdateStepType" Id="1" Type="DbKeeperNet.Engine.CustomUpdateSteps.MsSqlStepWithoutExplicitTransaction, DbKeeperNet.Engine"  FriendlyName="Setting up database schema for membership and roles">
      <Preconditions>
        <Precondition FriendlyName="Update step executed" Precondition="StepNotExecuted"/>
        <Precondition FriendlyName="Database is MSSQL" Precondition="DbType">
          <Param>MSSQL</Param>
        </Precondition>
      </Preconditions>
      <Param>DbKeeperNet.Extensions.MsSqlMembershipAndRolesSetup</Param>
      <Param>DbKeeperNet.Extensions.MsSqlMembershipAndRolesSetup.MsSqlMembershipAndRolesSetup.sql</Param>
    </UpdateStep>
    <!-- Create some seeded roles -->
    <UpdateStep xsi:type="upd:AspNetRoleCreateUpdateStepType" FriendlyName="Create role TestRole1" Id="2" RoleName="TestRole1"/>
    <UpdateStep xsi:type="upd:AspNetRoleCreateUpdateStepType" Id="3" RoleName="TestRole2"/>
    <!-- Seed an account and associate it with roles -->
    <UpdateStep xsi:type="upd:AspNetAccountCreateUpdateStepType" Id="4" UserName="TestUser1" Mail="testuser1@domain.com" Password="SeededPassword">
      <Role>TestRole1</Role>
      <Role>TestRole2</Role>
    </UpdateStep>
  </Update>
  <Update Version="1.01">
    <UpdateStep xsi:type="upd:AspNetAccountCreateUpdateStepType" Id="1" UserName="TestUser2" Mail="testuser2@domain.com" Password="SeededPassword2">
      <Role>TestRole1</Role>
    </UpdateStep>
    <!-- Delete the seeded role -->
    <UpdateStep xsi:type="upd:AspNetRoleDeleteUpdateStepType" Id="2" RoleName="TestRole2"/>
    <!-- Delete one of the seeded accounts -->
    <UpdateStep xsi:type="upd:AspNetAccountDeleteUpdateStepType" Id="3" UserName="TestUser1"/>
  </Update>
</upd:Updates>

Now let’s setup the C# portion which executes the script:

const string connString = "default"; // MsSql connection   
using (UpdateContext context = new UpdateContext())
{
    context.LoadExtensions();
    context.InitializeDatabaseService(connString);

    Updater updater = new Updater(context);
    updater.ExecuteXmlFromConfig();
}
Console.WriteLine("Can login as TestUser2: " + Membership.Provider.ValidateUser("Testuser2", "SeededPassword2"));
Console.WriteLine("Can login as TestUser2: " + Membership.Provider.ValidateUser("testuser2", "InvalidPassword"));
Console.WriteLine("Is user testuser2 in role testrole1: " + Roles.Provider.IsUserInRole("testuser2", "testrole1"));
Console.WriteLine("Is user testuser2 in role testrole2: " + Roles.Provider.IsUserInRole("testuser2", "testrole2"));

And appropriate App.Config portion:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="dbkeeper.net" type="DbKeeperNet.Engine.DbKeeperNetConfigurationSection,DbKeeperNet.Engine"/>
  </configSections>
  <dbkeeper.net loggingService="fx">
    <updateScripts>
<!-- This is the location of the DB Upgrade script - we use an embedded resource -->
      <add provider="asm" location="DbKeeperNet.AspNetMembershipDemo.DatabaseSetup.xml,DbKeeperNet.AspNetMembershipDemo" />
    </updateScripts>
    <databaseServiceMappings>
      <add connectString="default" databaseService="MsSql" />
    </databaseServiceMappings>
  </dbkeeper.net>
  <connectionStrings>
    <!-- Change this to correct absolute path for the demo or to an actual database -->
    <add name="default" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename='C:\Users\voloda\MyRoot\Development\GIT\DbKeeperNet\DbKeeperNet\Demos\DbKeeperNet.AspNetMembershipDemo\bin\Debug\DbKeeperNetAspNetMembershipDemo.mdf';Integrated Security=True;Connect Timeout=30;User Instance=True;Initial catalog=DbKeeperNetAspNetMembershipDemo" providerName="System.Data.SqlClient"/>
  </connectionStrings>
<!-- Let's enable MSSQL membership providers -->
  <system.web>
    <membership defaultProvider="AspNetSqlMembershipProvider">
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="default" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>
      </providers>
    </membership>
    <roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
      <providers>
        <clear/>
        <add connectionStringName="default" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
      </providers>
    </roleManager>
    <profile enabled="false">
      <providers>
        <clear/>
      </providers>
    </profile>
  </system.web>
</configuration>

References

History

  • Initial version

Friday, January 4, 2013

Letní dovolená Bedřichov 2012

Tak já vám teda řeknu jak to v tom létě 2012 na penzionu Uko bylo. Prý to má být krátké, úderné a výstižné. Mno uvidíme, ale vzhledem ke zpoždění to asi nebude problém.

Výlety


Pěšky na Královku


První výlet, na který jsme nadšeně vyrazili navzdory nic moc počasí byl na místní rozhlednu Královku.

Kryšťa si poctivě doťapal z penzionu až na místo i na rozhlednu, zatímco Macík se vezl v kočáru a chvílemi spokojeně podřimoval.

Obídek (první svíčkovou) jsme si dali v restauraci přímo pod rozhlednou. Bohužel se jednalo o zážitek dosti otřesný (všechno špatné je pro něco dobré a tak byla laťka nasazena dostatečně nízko, aby se to už neopakovalo).

A aby toho nebylo málo tak jsme cestou zpátky zmokli.

Poprvé na tyči

Tyč pro Kryšťu jsme pořídili v den odjezdu. Nejdřív jsme ji vyzkoušeli jenom kolem penzionu, ale další den jsme vyrazili na velký výlet.
Na kole jsme dojeli až k Bedřichovské přehradě na Černé Nise (celkem cca 11km), kde jsme posvačili. Cestou Kryšťa zbaštil spooooustu borůvek.


Na kole a autem směr koně

S Kryšťou na tyči jsme vyrazili směrem do kopce od penzionu (ono to vlastně ani jinak nešlo :-)). Koně byli na chatě Dřevona kde Kryšťa byl vloni na dovolené s babičkou, dědou, Víťou a Lenou.

Mezitím vyrazila máma autem spolu s Macíkem na parkoviště nahoře u kapličky.

Kryšťa si dal kolečko kolem kapličky na poníkovi s tátovým doprovodem, pak jsme zajeli na oběd.

S Kryšťou jsme sfrčeli z kopce zpátky k penzionu. Tam jsme dloooooouho čekali na návrat auta. Máma dorazila krapet vzteklá s nabouraným nárazníkem. Ten se ale naštestí sám od sebe vrátil do původního stavu a tak máme na autě jenom malou památku v podobě světlého kolečka na levém předním nárazníku.

Na kole směr přehrada podruhé (tentokrát Josefovská)

Znovu na tyči jsme vyrazili na další přehradu. Máma tentokrát neriskovala a vyrazila radši jenom pěšky s kočárem. Než dorazila, tak Kryšťa posvačil, naházel kamínky do přehrady a pečlivě vyčistil chodník od mechu.

Konečně i Babylón


Do centra Babylon a jeho IQ parku jsme vyrazili poté, co jsme se navnadili na hlavolamech u Janovské bobové dráhy (tam nás s Kryšťou nejvíc bavil jeřáb ze 4 provázků).

V IQ centru měli spoustu zajímavých věcí - bublifuk na lidi, ozubená kolečka, která se dala skládat jak bylo potřeba, fakírskou hřebíkovou postel, na kterou se dalo lehnout, různá hejblátka a udělátka.

Sklárna čili Ajeťáci

Ve sklářském kraji je třeba navšívit i sklárnu. Pro náš výlet jsme si nakonec vybrali jednu trochu dál se sklářskou krčmou jménem AJETO.

V krčmě měli vše klasicky smažené, ale zato jako turistickou atrakci si každý mohl vyfoukat sklo. Kryšťa vyrobil vázy pro babičky a máma dostala k narozeninám půlitr na pivo (byli jsme tam 31.7. :-)).

Turistuv ráj alias Výletní areál Pěnčov

Areál se nachází kus od našeho oblíbeného Železného Brodu a plátěnky.
Za pár párů stokorun a něco navrch z nás vytřásli duši ve vláčku směrem na rozhlednu Krásná. Cestou zpět jsme měli povinnou zastávku v, abychom si mohli prohlédnout ruční výrobu skleněných figurek (nebo spíš aby si naše zadky odpočinuly, kdoví).

Když nás vláček dotřásl až zpátky, dali jsme si dobrý obídek hned u farmy. Výlet jsme zakončili k velké Kryšťově a malé mojí radosti v kozím výběhu (nevím proč, ale živé kozy mi nikdy nepřirostly k srdci - asi proto, že tolik smrdí).

Bouda na velikém kopci (Nová louka)

Tak tenhle výlet na tyči byl mazec - cestou jsme vyjeli stoupání 11°. Kryšťa šlapal jako o život a tak jsme předjeli několik dalších cyklistů.

Nahoře měli ve stánku malinovou limošku a výbornou (klo)básu.

Cestou zpátky jsme nasbírali borůvky pro mámu a Macíka (Kryšťa si při sbírání nedal ani jednu).

Konečně Ještěd a další svíčková

Uvěřili jsme dědově navigaci a vyrazili směr Ještěd přesně opačně než ostatní. Kupodivu jsme nakonec na parkovišti byli dřív.
Kabinková lanovka na Ještěd byla pěkně nacpaná, ale mají to dobře zařízeno - s kočárkem nás pustili o chvilku dřív než ostatní zadním vchodem a tak jsme se pohodlně vešli.

Na kopci byla krásná vyhlídka. Bohužel jsme zkusili vhodit pár mincí do nefunkčního dalekohledu (ten Kryšťa zná z oblíbené traktorové hry a tak jsem mu ho chtěl ukázat).

Nakonec jsme si šli dát obídek do restaurace. Macíkovi ohřáli jeho baštu a všichni jsme si nakonec ještě trochu pohráli v dětském koutku (Kryšťa se nám tam krapet popral s jedním mrňousem co mu bral hračky - mně se dostalo ponaučení, že pokud si potomek chce s něčím hrát v herně musí rodič na dotyčné věci držet ruku)

Ubytování

Tak tohle byla asi nejlepší část dovolené:
  • Velice příjemná obsluha restaurace vždy ochotná a usměvavá
  • Bezproblémové řešení reklamací
  • Dětská hřiště v penzionu jsou skutečně funkční
  • Bazén opravdu fungoval včetně výřivky
  • Užili jsme si i sauny (super atrakce bylo ledové vědro - dřevěné vědro s napouštědlem ze záchodu, které si člověk oklopil na hlavu hned jak vylezl ven). V sauně byl i Kryšťa
  • Do restaurace dosáhla chůvička z pokoje a všude navíc fungoval v pohodě internet
  • Vlastně fungovalo všechno co bylo na webu
  • Kryšťa jednoho dne z ničeho nic vylezl na kolmou lanovou stěnu (poprvé) :-)

Cyklistika

Z mého pohledu skvělá cyklistická dovolená. Horské výlety cca 50-90km:
  • Bedříchov - Liberec - Ještěd a zpět
  • Bedříchov - Harrachov a zpět
  • Bedříchov - Železný Brod - Huntířov - a zpět (tohle byla obzvlášť vypečená cesta - zpátky jsem se vrátil jako vodník protože v Jablonci začalo pekelně pršet)
  • Bedříchov - Tanvald a zpět (celá řada různých variací na toto téma)
  • Bedříchov - Josefovská přehrada - Les - Hřebeny - a zpět (opět několik variací na toto téma, jedna se stoupáním cca 19% po lesní cestě na silničních pneu)

Odkazy

Babiččiny květákové placičky


  • Květák rozebrat na růžičky a uvařit do měkka v osolené a okmínované vodě (cca 15 minut)
  • Po uvaření květák scedit a nechat okapat
  • Okapaný květák rozmačkat šťouchadlem na brambory
  • Vmíchat vejce, osolit, opepřit, okmínovat, vmíchat trochu strouhanky
  • Možno ještě obalit v trojobalu jako řízek
  • Osmažit na pánvi jako řízek

Wednesday, September 21, 2011

How to release non-managed library loaded into managed .NET code

Motivation

I had found this article on how to release DLL library already loaded into the process using P-Invoke. It uses LoadLibrary() and FreeLibrary() WINAPI calls to achieve this.

And what is wrong with it?

It forces to unload ALL instances of the DLL library currently loaded within process. Which means, that in the case you have more than one instance of the class using these external functions ALL these will stop working!

And that is not all - you cannot use this DLL in same application domain again after unloading.

Solution

Solution is pretty simple one, but I have to say that it wasn't very obvious to me at the beginning.
You can use P-Invoke to import following standard WinAPI functions for dynamical function loading:
  • LoadLibrary()
  • FreeLibrary()
  • GetProcAddress()
We will use following wrapping class:

internal static class UnsafeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static IntPtr LoadLibrary(string libraryName);
    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static bool FreeLibrary(IntPtr hModule);
    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static IntPtr GetProcAddress(IntPtr hModule, string procName);
}

We also need signatures of imported functions - we will convert them into delegates (following ones come from sample project):
// int multiply(int value1, int value2);
private delegate int MultiplyDelegate(int value1, int value2);
// int str2int(const char *input);
private delegate int Str2IntDelegate([MarshalAs(UnmanagedType.LPStr)]string source);

Now we can create implement our class calling external DLL functionality with IDisposable interface so it will automatically release used DLL library when it will go out-of-scope or it will be finalized (in example project are two functions which we will publish as Multiply() and Str2Int()).

public class ExternalHelpers: IDisposable
{
    #region Private members
    private IntPtr _libraryHandle;
    private MultiplyDelegate _multiply;
    private Str2IntDelegate _str2Int;
    #endregion

    #region External functions delegates
    // int multiply(int value1, int value2);
    private delegate int MultiplyDelegate(int value1, int value2);
    // int str2int(const char *input);
    private delegate int Str2IntDelegate([MarshalAs(UnmanagedType.LPStr)]string source);
    #endregion

    public ExternalHelpers()
    {
        // dynamically load DLL using WinAPI
        _libraryHandle = UnsafeMethods.LoadLibrary(@"testing.dll");

        if (_libraryHandle == IntPtr.Zero)
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        // import functions as delegates using GetProcAddress
        _multiply = LoadExternalFunction<MultiplyDelegate>(@"multiply");
        _str2Int = LoadExternalFunction<Str2IntDelegate>(@"str2int");
    }

    public int Multiply(int value1, int value2)
    {
        // call method using delegate
        return _multiply(value1, value2);
    }

    public int Str2Int(string source)
    {
        // call method using delegate
        return _str2Int(source);
    }

    public void Dispose()
    {
        Dispose(true);

        GC.SuppressFinalize(this);
    }

    ~ExternalHelpers()
    {
        Dispose(false);
    }

    #region Private helper methods
    private T LoadExternalFunction<T>(string functionName)
        where T: class
    {
        Debug.Assert(!String.IsNullOrEmpty(functionName));
        // load function pointer
        IntPtr functionPointer = UnsafeMethods.GetProcAddress(_libraryHandle, functionName);

        if (functionPointer == IntPtr.Zero)
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        // Marshal to requested delegate
        return Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(T)) as T;
    }

    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            _multiply = null;
            _str2Int = null;
        }

        if (_libraryHandle != IntPtr.Zero)
        {
            if (!UnsafeMethods.FreeLibrary(_libraryHandle))
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
                
            _libraryHandle = IntPtr.Zero;
        }
    }
    #endregion
}

And finally - we can use it:

static void Main(string[] args)
{
    using(ExternalHelpers e = new ExternalHelpers())
    {
        const int value1 = 2;
        const int value2 = 3;
        const string strValue = "345";

        Console.WriteLine("{0} * {1} = {2}", value1, value2, e.Multiply(value1, value2));
        Console.WriteLine("{0} => {1}", strValue, e.Str2Int(strValue));
    }

    Console.ReadKey();
}

Looks easy? Yes it is :-)

Links

Sunday, September 11, 2011

Dovolená Deštné v Orlických horách

Na dovolené v Deštném nám skoro nepršelo. S sebou jsme vezli dvě kola, dětskou sedačku na kolo, kakao a jinak skoro nic. Bydleli jsme v malé horské chatičce s akumulačníma kamnama, které nám paní z kempu druhý den zapnuly. A tak jsme od druhého dne měli trvale krapet horko (přeci jenom než jsme si zvykli na jejich setrvačnost, tak nám to trochu trvalo).

Kemp celkově byl úžasný, jenom to pivo a jídlo v kempové restauraci bylo trochu slabší. Kempové paní byly moc hodné a ochotné. Pro děti tam měli velký kulatý stan na hraní, klouzačky, trampolínu a dětský koutek v hospodě, v lese bylo dřevo na táborák a pod okny tekl potůček. Ze zahrádky byl výhled rovnou na dětské hřiště. A po celém kempu opravdu fungoval zdarma internet.

Ke snídani jsme si dávali na co jsme měli chuť - vajíčka, párečky, šunčičku a Kryšťovi tam vařili jeho oblíbené kakó. Obědy jsme si dávali různě tam, kde jsme zrovna byli na výletě a na večeře jsme většinou chodili do restaurací po okolí. Tam taky měli děti rádi. Kryštoví se nejvíc líbilo v protějším penzionu, kde hladil ježečka.

Kryšťa si vymyslel, že chce jet lanovkou a tak jsme nakonec dvakrát jeli na lanovku do Říček, kde se na kopci cpal borůvkami a dokonce tam ušel nějaký ten kilometr (trochu s brekem, ale to nám velkým nevadilo). Celý týden jsme se snažili sbírat pohádková razítka.

Jednou jsme šli pěšky ze Šerlichu na chatu Šerlišský mlýn (no dobrá - bylo to s kopce a tak to odťapal i Kryšťa. Tomu se na Šerlišském mlýně líbil hlavně systém jezírek a potůčků, kde pilně studoval fyzikální zákony vodních proudů. K obědu jsme si tam dali svíčkovou a sladké knedlíky. Paní servírka tvrdila, že už tam pracuje 30 let, takže jsem ji tam nejspíš potkal i během všech předchozích návštěv (jednou když jsem byl malý - taky mám dětskou fotku od mlýnského kola, jednou s Terkou na kole a teď jsme tam byli potřetí).

Krom toho jsme také byli na výletě v Polsku. Tam jsme si prošli rašeliniště, neboli Torfovisko, 5krát s Kryšťou vylezli na vyhlídkovou věž a tak.

Zajeli jsme se podívat i za tetou Monikou do Letohradu. Cestou jsme měli drobnou blinkací nehodu v serpentinách (nějak jsme nepochopili, že chci domů znamená chci blinkat). V Letohradě jsme navštívili muzeum řemesel, kde jsme půl hodiny pouštěli betlém, teta Monika nám ukázala svůj luk a kytaru.

Na Častolovickém zámku jsme si prohlédli nádvoří a hlavně park s divokým prasetem, srncem a jelenem a taky minizoo (v té měli mini prasátka).

Já jsem si užil i kolo, přeci jenom není nad horskou silniční cyklistiku.

Výlety
  • Lanovka s letním provozem v Říčkách v Orlických horách
    • Káry
    • Koloběžky
    • Pro pěší cesta nahoru za mírný poplatek, dolů zdarma, provoz pouze v celou hodinu, nahoře prima borůvky
  • Šerlich - Masarykova chata
    • Nahoře na Šerlichu je parkoviště, kde se nechá zastavit, následuje příjemná procházka z kopce dolů na chatu Šerlichův mlýn, kde mají vodní kolo, vodníka a jezírka.
  • Zámek Častolovice
    • Tady mají mini-zoo a zvěřinec a taky jelena a divoké prase.
    • Prohlídku zámku jsme vynechali.
  • Letohrad 
    • Muzeum řemesel s pohyblivým betlémem řemesel
  • Torfovisko
    • malá procházka rašeliništěm cca 30km od kempu v Polsku. Krásná vyhlídková věž, na kterou jsme několikrát vylezli. Bohužel cesta zpátky vyžaduje kvůli jednosměrce objížďku cca 15km.

Cyklistika

Cyklistika (tedy ta moje oblíbená - silniční) neměla chybu. Zejména pro milovníky kopců - v okolí Deštného totiž neexistuje rovinka a tak prostě člověk jezdí pořád nahoru a dolů, ale stojí to za to. Projížďky dále jsou víceméně na 2 - 2.5 hodiny ostřejší jízdy, ale musím říct, že jsem se nenudil. Nejnáročnější výjezd je asi na Šerlich, ale na druhou stranu pak následuje krásný dlouhý sjezd.

Deštné - Nedvězí - Kounov - Dobruška - Opočno - Trnov - Solnice - Skuhrov nad Bělou - Deštné
59km, převýšení 1098 m, v Dobrušce je nejbližší lékárna od Deštného.

Deštné - Šerlich - Říčky - Rokytnice - Nebeská rybná - Deštné
54 km, převýšení 1280m

Deštné - Zdobnice - Rokytnice v Orlických Horách - Rychnov nad Kněžnou - Solnice - Skuhrov - Deštné
62km, převýšení 1312m
Deštné - Šerlich - Orlické Záhoří - Zieleniec (PL) - Olešnice - Sedloňov - Dobřany - Deštné
54 km, převýšení 1157m

Kemp