Category Archives: Vista és .NET 3.0

Jeffrey Snoverrel beszélgettem

A TechEd kaliberű rendezvények egyik előnye, hogy az ember személyesen találkozhat azokkal, akik igazán közel vannak a tűzhöz. Ez persze nem minden téma esetén van így, mert vannak termékek, ahol az "evangélisták" tartják az előadásokat, de a kisebb csapatok esetén az előadók gyakran egyben a projekt szakmai agyai is.

Így történt ez az idei TechEden is, ahol a PowerShell előadást maga Jeffrey Snover tartotta, akit egyben a PowerShell atyjának is tartanak. A téma egyébként a PowerShell 2 volt, amire mindenképp érdemes figyelmet fordítani. Hogy csak két dolgot említsek: távoli adminisztráció és grafikus felület a commandletek írásához. Jól hangzik, nem? 😉

Őt sikerült a Speaker Lounge-ban egy igen érdekes beszélgetésre elkapnom, ahol számos újdonságot elárult mind a PowerShell 2-ről, mind pedig arról, hogy hogyan működik ez a fejlesztő csapat a Microsofton belül. Ennek a beszélgetésnek a nem NDA-s részéről felvételt is készítettem, ami megtekinthető az MSDN Kompetencia Központ oldalán az alábbi képre kattinva:

Jeffrey Snover interjú

A PowerShell csapat egyébként tényleg nem nagy, mindössze körülbelül harmincan dolgoznak azon az eszközön, ami a közeljövőben minden szerver termékben jelen lesz. Az Exchange 2007 már használja, és már az SQL Server 2008 CTP változatát is lehet szkriptelni. Ja kérem, úgy könnyű, ha az ember mögött ott áll a fővezér, Bob Muglia, aki komolyan hisz a PowerShellben 🙂

Íme néhány tipp a kezdeti lépések megtételéhez:

  1. PowerShell letöltése
  2. A telepítő feltesz néhány rövid doksit (külön is letölthetőek), azokat érdemes átböngészni
  3. Ingyenes e-Book Frank Kochtól
  4. Könnyen emészthető könyv a PowerShell: Step-by-Step az MS Presstől

Ennyi után már bátran nekivághatunk saját szkriptek írásának, bár fejlesztőkhöz inkább a saját commandletek készítése illik, de erről majd legközelebb…

 

Technorati tags: , ,
Advertisements

Workflow Foundation hosztolása ASP.NET-ben

Hear me speak at TechEd Developers 2007 Ha már Lipi volt olyan kedves és Világszám! címmel blogbejegyzést írt a TechEd előadásomról, igazán tartozom némi bővebb információval az itthon maradottak számára.

A dolog úgy kezdődött, hogy a tavaly novemberi MSDN konferencia után jobban beleástam magam a Windows Workflow Foundation és az ASP.NET kapcsolatába, amiről pár rövidebb blogbejegyzést írtam is (lásd hosting és threading). Mélyebbre ásva magam a témába hamar kiderült, hogy WF-et ASP.NET-ben hosztolni bár lehet, csak mazochistáknak ajánlott. Erőltetés a köbön. Sokkal ésszerűbbnek tűnik helyette egy Windows service-t írni és a webalkalmazásból remotingon keresztül kommunikálni vele.

Akárhogy is, nem lehet elmenni amellett, hogy a Microsoft szerint a WF minden fajta CLR AppDomainben hosztolható. Bár ez kétségkívül igaz és a VS által generált projekt típusokban simán működik is, ASP.NET-ben visszatérő fejfájást okozhat. Végigküzdve magam némi kódon rájöttem, hogy nem egyszerűen a hosztolás a gond. A probléma részét képezi az, hogy a webfejlesztők nem akarnak tudni a WF-ről, a workflow fejlesztők pedig nem akarják, hogy az ASP.NET guruk belepiszkáljanak a kódjaikba. A hosztolás technikai igényei mellett figyelembe venni ezt az igényt is, nem egyszerű olyan architektúrát találni, ami ideálisnak mondható. Az ExternalDataExchange-re épülő kommunikáció annyira nyakatekert, hogy nem triviális szétvágni a kódot fejlesztői szerepkörök és felelősség szerint.

Összeszedtem néhány kényes területet, és erről beadtam egy előadás javaslatot a TechEdre, amit el is fogadtak:

  • WF és ASP.NET technológiák összekapcsolása
  • WF és ASP.NET specifikus kódok szétválasztása
  • Szálkezelés
  • Hosszú ideig futó (long running) folyamatok
  • Szekvenciális vagy állapotgép?
  • Hosszú ideig futó activity-k
  • Eseményvezérelt activity-k
  • Kommunikáció
  • Monitorozás

Ha pedig már ott voltam, akkor "jól kihasználtak" és még egy másik előadásra is felkértek a workflow kommunikációs infrastruktúrával kapcsolatban. Ha van rá igény, egyszer szívesen leírom, hogy milyen egy ilyen méretű konferencia előadói szemmel.

Visszatérve az eredeti témára, az Avoiding Pitfalls When Hosting Windows Workflow Foundation in Real World ASP.NET Applications című előadás úgy látszik többeket szíven talált, mert sokan kérték a demó alkalmazás forráskódját, amit az MSDN Kompetencia Központ oldalán meg is osztok minden érdeklődővel. A példa egy ASP.NET standard regisztrációs oldalt egészít ki egy workflow-val, amivel ellenőrizzük a felhasználó e-mail címét és beépítünk még egy manuális jóváhagyást vagy elutasítást is. Nem bonyolult, de sok problémát érint. Lehet benne példát találni nem csak a hosztolásra, hanem a kommunikációra, állapotgépre és hosztolásra is, sőt még arra is, hogy a folyamat aktuális állapotát hogyan jeleníthetjük meg egy weboldalon grafikusan.

Minden visszajelzést szívesen fogadok!

 

CD írás távolról

Délután úgy hagytam ott a tanszéki gépemet, hogy még egy VPC image-et tömörített, betettem egy üres lemezt az íróba, gondoltam mire hazaérek kész lesz és majd otthonról elindítom a DVD írást. Csak hogy miután remote desktoppal beléptem és elindítottam a Nerot, ezzel a barátságos hibaüzenettel fogadott:

If you are running Nero burning software via Windows remote login, you might not be able to access your drives for burning. This is a security restriction from Windows.

Próbáltam Disc Infot kérni, de azt mondta, nincs lemez a meghajtóban. Hurrá, sikerült a gépnek megvédenie magát tőlem. Lehetséges megoldások:

  • Nero indítása "eleválva": Run As Administrator.
  • Helyi házirend megpiszkálása, hogy ez többet ne forduljon elő, hiszen legközelebbre úgyis elfelejtem, mi volt a megoldás: Group Policy Editor –> Computer Configuration –> Administrative Templates –> System –> Remote Storage Access –> All Removable Storage: Allow direct access in remote sessions = Enabled.

 

Technorati tags: , ,

WorkflowInstanceId kötése

Aki csinált már olyan workflowt, amelynek kommunikálnia kellett a külvilággal, annak lehet, hogy szüksége volt arra, hogy a workflow egyedi azonosítóját átadja egy activitynek vagy egy külső komponensnek. Az "átadás" nem jelenthet gondot, hiszen a Workflow Designer okos jószág, lehet benne tulajdonságokat kötögetni.

Sajnálatos módon azonban a WorkflowInstanceId tulajdonságot nem kínálja fel, hiába keresünk System.Guid típushoz párt. Mit tehet ilyenkor az egyszeri workflow programozó: definiál egy tulajdonságot, ami majd becsomagolja ezt a hívást, a tulajdonságot pedig public láthatóságra állítja, hogy köthető legyen:

    public Guid CurrentInstanceId
    {
        get
        {
            return this.WorkflowInstanceId;
        }
    }

Ettől kezdve azonban furcsa jelenségek ütik fel a fejüket, mintha minden a feje tetejére állt volna, például:

  • A workflow példány tökéletesen lefut, de az utolsó activity utáni pillanatban mégis elszáll, pedig oda nem is írtunk kódot.
  • A workflow példány az élete végén 100%-ra terheli a processzort.
  • Elszáll az alkalmazásunk, mert eddigi tökéletesen működő helyen azt a hibaüzenetet kapjuk, hogy az adott művelet csak workflow runtime threaden hajtható végre.
  • A Visual Studio debug módban nem képes megmutatni a workflowt, mert szerinte valami érvénytelen művelettel próbálkozunk, amit csak futási időben lehet elvégezni.

Mindennek az oka pedig ez a kis ártatlannak tűnő tulajdonság. De mi lehet a háttérben? Gondoljunk arra, hogy a this.WorkflowInstanceId tulajdonság kiolvasásának akkor van értelme, ha a workflow példány fut és a workflow runtime tud róla. Vannak azonban olyan pillanatok, amik nem esnek ebbe a csoportba, a Workflow Foundation mégis megpróbálja kiolvasni a workflow példány tulajdonságait. Ez történik például akkor, amikor a WorkflowRuntime.WorkflowCompleted eseménykezelőnek megpróbál átadni egy WorkflowCompletedEventArgs paramétert. Ebben az e paraméterben ugyanis van egy OutputParameters tulajdonság, ami egy szótár típusú gyűjteményen keresztül teszi elérhetővé a workflow példány tulajdonságait. Amikor a rendszer megpróbálja felépíteni ezt a dictionary-t, akkor bizony a workflow példányunk már éppen nem él.

Mit tehetünk akkor, ha mindenáron kötni szeretnénk a folyamat egyedi azonosítóját? Készíthetünk egy publikus property-t, ami nem közvetlenül a this.WorkflowInstanceId tulajdonságot olvassa ki, hanem egy olyan változó tartalmát, ahova korábban már átmásoltuk ezt az értéket. Ha biztosak vagyunk abban, hogy ezt a tulajdonságot a workflow példány futása közben valamelyik activity kiolvassa, akkor írhatjuk például ezt:

    private Guid _instanceId;

    public Guid CurrentInstanceId
    {
        get
        {
            if( this._instanceId.Equals( Guid.Empty ) )
            {
                this._instanceId = this.WorkflowInstanceId;
            }
            return this._instanceId;
        }
    }

Általában érdemes odafigyelni a tervezésnél, hogy egy döglött workflow példányról már csak a tracking service segítségével szerezhetünk információkat.

 

Technorati tags: , ,

Elbénázott workflow verzió frissítés – Nézz és láss!

A minap hozzá kellett nyúlnom egy korábbi Workflow Foundationös projekthez, aminek a verziószámát szépen meg is növeltem a módosítás után. A biztonság kedvéért nyomtam a Studioban egy Rebuild Solutiont, mégis az alkalmazás első futtatásakor ezt a hibaüzenetet kaptam:

Could not load file or assembly ‘Sample.Workflows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

A fene, valami nem jól frissült. Nosza, újrafordítottam a solution minden egyes projektjét. Semmi javulás. Letöröltem majd újra hozzáadtam a szerelvény referenciákat, a hibaüzenet változatlan. Letöröltem a bin és obj mappákat. Ugyanaz a szöveg. Kibányásztam a Windows mappából a Temporary ASP.NET Files mappát és abból is kitakarítottam mindent, de ez sem segített.

Ekkor kezdtem el gyanakodni, hogy rossz helyen keresem a hibát és ekkor ugrott be a hibakeresés első számú alapszabálya: olvasd el a hibaüzenetet, az egészet, elejétől a végéig!

Nézzük meg, melyik sornál keletkezik a hiba! Ez volt a bűnös:

StateMachineWorkflowInstance instance = new StateMachineWorkflowInstance( runtime, workflowInstanceId );

Ezen nincs mit hibáztatni, ennek tényleg kell a workflow típus a szerelvényből. Olvassuk csak végig a hibaüzenetet, ha már rászántuk magunkat. Na de mi van egy .NET-es hibaüzenet végén? A stack trace a maga hosszú és unalmas formájában, jelen esetben ez:

[FileLoadException: Could not load file or assembly ‘Sample.Workflows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)]
   System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +0
   System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +211
   System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +141
   System.Reflection.Assembly.Load(String assemblyString) +25
   System.UnitySerializationHolder.GetRealObject(StreamingContext context) +355
   System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder) +61
   System.Runtime.Serialization.ObjectManager.DoFixups() +2599325
   System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) +203
   System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) +190
   System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) +12
   System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity, IFormatter formatter) +219
   System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity) +52
   System.Workflow.Runtime.Hosting.WorkflowPersistenceService.RestoreFromDefaultSerializedForm(Byte[] activityBytes, Activity outerActivity) +114
   System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService.LoadWorkflowInstanceState(Guid id) +249
   System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor, WorkflowInstance workflowInstance) +607
   System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, CreationContext context, WorkflowInstance workflowInstance) +268
   System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId) +148
   System.Workflow.Activities.StateMachineWorkflowInstance..ctor(WorkflowRuntime runtime, Guid instanceId) +126
   WorkflowManager.GetCurrentState(Guid workflowInstanceId) in c:Documents and SettingsdemoDesktopAspNetWFDemoSolutionWebApp_CodeWorkflowManager.cs:187
   Admin_Default.GetState(Object comment) in c:Documents and SettingsdemoDesktopAspNetWFDemoSolutionWebAdminDefault.aspx.cs:46
   ASP.admin_default_aspx.__DataBinding__control18(Object sender, EventArgs e) in c:Documents and SettingsdemoDesktopAspNetWFDemoSolutionWebAdminDefault.aspx:41
   System.Web.UI.Control.OnDataBinding(EventArgs e) +99
   System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +206
   System.Web.UI.Control.DataBind() +12
   System.Web.UI.Control.DataBindChildren() +216
   System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +216
   System.Web.UI.Control.DataBind() +12
   System.Web.UI.Control.DataBindChildren() +216
   System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +216
   System.Web.UI.Control.DataBind() +12
   System.Web.UI.WebControls.GridView.CreateRow(Int32 rowIndex, Int32 dataSourceIndex, DataControlRowType rowType, DataControlRowState rowState, Boolean dataBind, Object dataItem, DataControlField[] fields, TableRowCollection rows, PagedDataSource pagedDataSource) +221
   System.Web.UI.WebControls.GridView.CreateChildControls(IEnumerable dataSource, Boolean dataBinding) +3004
   System.Web.UI.WebControls.CompositeDataBoundControl.PerformDataBinding(IEnumerable data) +59
   System.Web.UI.WebControls.GridView.PerformDataBinding(IEnumerable data) +11
   System.Web.UI.WebControls.DataBoundControl.OnDataSourceViewSelectCallback(IEnumerable data) +111
   System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +29
   System.Web.UI.WebControls.DataBoundControl.PerformSelect() +149
   System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +70
   System.Web.UI.WebControls.GridView.DataBind() +4
   System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +82
   System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls() +69
   System.Web.UI.Control.EnsureChildControls() +87
   System.Web.UI.Control.PreRenderRecursiveInternal() +41
   System.Web.UI.Control.PreRenderRecursiveInternal() +161
   System.Web.UI.Control.PreRenderRecursiveInternal() +161
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1360

Ez a hívási lánc önmagában is megérne egy misét és ezt látva talán nem meglepő, hogy a fejlesztők többségéhez hasonlóan én is csak az elejét és a végét néztem meg, abból pedig nem derült ki semmi. 😦

A bőnös pedig ott van a stack trace kellős közepén: WorkflowPersistenceService.RestoreFromDefaultSerializedForm. Ahhoz, hogy egy StateMachineWorkflowInstance példányt kapjunk, a runtime-nak szüksége van a workflow példányra (lásd GetWorkflow fent), amihez természetesen be kell tölteni azt a memóriába (Load), ami jelen esetben azt jelentette, hogy a persistence store-ból vissza kellett állítani a workflow példány állapotát (LoadWorkflowInstanceState). Csakhogy a persistence service sorosításkor eltárolja a workflowt tároló szerelvény teljes nevét, így a verziószámát is, és a visszatöltéskor az alapján próbálja visszaállítani az objektumot sorosított formából.

Tehát ha megváltoztatunk egy workflow definíciót (osztályt), akkor mindig gondoljunk arra, hogy az alapján a definíció alapján már futhatnak workflow példányok, amelyek sorosítva szunnyadnak valamilyen persistence vagy tracking adatbázisban. A friss szerelvényt gond nélkül fogjuk tudni telepíteni és új workflow példányokat is simán fogunk tudni indítani. A hiba csak akkor fog előállni, amikor egy csontváz kiesik a szekrényből: feléled egy várakozó workflow.

 

Haszontalanságok

Minden fejlesztő rémálma, amikor a projekt vezetők kitalálnak olyan funkciókat egy alkalmazásba, amiről messziről látszik, hogy senki nem fogja használni. Ennél már csak az tud zavaróbb lenni, amikor a fejlesztő lelkesedik be és beépít valami olyat a szoftverbe, ami teljesen felesleges, pláne, ha még rosszul is működik.

Ezen cikk apropóját egyébként az adta, hogy a Microsoft Regional Directors levlistán már se szeri se száma az alábbi képeknek:

Vista: About 86 Days and 11 hours remaining

Sőt, van még rosszabb is:

Vista: About 44842 Days and 21 hours remaining

De a teljesség kedvéért el kell mondanunk, hogy vannak optimista pillanatai is a rendszernek:

Vista: About 5 seconds remaining

A Vista SP1 (még béta) egyébként nem sokat javít a rendszeren, de ezt a jelenséget tényleg visszaszorítja (nem azt mondtam, hogy javítja!).

Visszatérve a kezdeti témához: vajon tényleg szükség van erre? Ki a fene találta ki, hogy ebben a dialógus ablakban a  hátralévő időnek meg kell jelennie? Az egésszel nem is lenne baj, ha dolgozna mondjuk 3 másodpercig és az alapján megsaccolná, hogy mennyi van még hátra. De nem, ez vacakol cirka 20 másodpercig, hogy aztán végre füllentsen valamit, majd nagy nehezen elkezdi az érdemi munkát. Legalábbis ez látszik, és az számomra a felhasználói élmény mélypontja.

Ha nekem kellene ilyen ablakot alkotni, én nagyon erősen ragaszkodnék a százalékos megjelenítéshez: átment bájtok száma / átviendő bájtok száma = éppen 27%. Kész. Aki nagyon akarja, rajzoljon alá kígyót.

De persze olyan kígyó legyen, ami csak növekszik és nem megy össze ijedtében. Szerintem mindannyian láttuk már olyan telepítőt, ami:

  • több csíkot húz,
  • egy darabig növeli a csíkot, majd aztán az visszamegy,
  • baromira nem találja el, hogy mikor lesz vége a telepítésnek.

Nem mondom, egy telepítőt megírni nem egyszerű dolog. Még egy-egy lépésének az idejét sem lehet egyszerűen megsaccolni, azt meg még nehezebb, hogy az egész mikor lesz kész. De vajon valóban az idő a fontos? Vajon miért nem lehet oda azt írni, hogy 3. lépés a 89-ből, vagy oda is egy százalékot. Az legalább pontos lenne és elég gyakran változna ahhoz, hogy egyértelmű legyen: a szoftver dolgozik és nem fagyott le (még).

Ennyi bénázás és átverés után már egyszerűen nem hiszek ezeknek a csíkoknak, nem is érdekelnek, sőt mi több, egész egyszerűen zavarnak. Gondolt már valaki arra, hogy az animáló zöld csíkot hány napon keresztül álmodták meg a grafikusok, majd építették be a programozók, hagyták jóvá a tesztelők, szívtak vele a felhasználók, akik jelentették a terméktámogatáson keresztül, hogy aztán ott felvigyék egy bug adatbázisba, ami alapján végül a programozók kijavítják – hogy aztán kör kezdődhessen szinte elölről?

Csak én gondolom úgy, hogy az egész teljesen felesleges, vagy más szerint is mindenki jobban járt volna, ha azon a pénzen az állatvédőket vagy a Vöröskeresztet támogatják?

Jogosultságosztás ACL-lel

Előzmény: telepítő alkalmazás jól működik angol Windowson, elszáll magyaron. Vajon mi lehet az oka? Némi búvárkodás után egyáltalán nem meglepő eredményre jutottam: a Felhasználók.

Ha jogosultságokat szeretnénk állítgatni egy mappán .NET-ből, akkor 2005 óta örülhetünk, mert a .NET 2.0 már támogatja hozzáférés szabályozási listák, azaz ACL-ek (Access Control List) kezelését. Rá is kattanhatunk rögtön a FileSystemAccessRule osztályra és nem lepődünk meg, hogy a konstruktor első paramétere egy SID, azaz security identifier. Nagyon szép, hogy a SID-ek leírására létezik egy SecurityIdentifier osztály a System.Security.Principal névtérben és milyen egyszerű a konstruktornak paraméterként megadni, hogy például a @"BUILTINUsers" csoportra vagyunk kíváncsiak. Király, hogy van BUILTIN, mert így nem kell bedrótoznunk a gépnevet, ám miközben ennek örülünk, sikerült bedrótoznunk a Users csoport nevét. És hasonlóan lehet például az Administrator vagy a Network Service fiókról is szó. Mi ezekben a közös? Hogy más operációs rendszereken máshogy hívják őket, konkrétabban van Rendszergazda, Network Service és vannak Felhasználók is.

Végignézve a bevezetőben említett kódot, azért dobott exceptiont, mert a Users csoport nem létezik magyar Windowson, ott ugyanis Felhasználóknak hívják. Most akkor drótozzuk be az összes lehetséges értéket?

A megoldás ennél azért szebb, köszönhetően annak, hogy bármennyire is azt szoktuk mondogatni, hogy a SID egyedi, valójában nem az. A minden gépen létező csoportoknak és felhasználóknak ún. well-known SID-jük van, azaz előre lehet tudni őket. A jó hír az, hogy létezik egy CreateWellKnownSid nevű Win32 API függvény, ami képes visszaadni ezeket az ismert SID-eket és hogy még szebb legyen a kép, ezt meg lehet hívni P/Invoke-kal .NET-ből, sőt mi több, a SecurityIdentifier osztály helyből képes erre, ha a WellKnownSidType paraméterezésű konstruktorát használjuk.

Ezek alapján tehát például így hozhatunk létre mappát úgy, hogy a Felhasználók csoportnak biztos Full Control joga legyen rajta:

    Directory.CreateDirectory( path );
    DirectoryInfo dirInfo = new DirectoryInfo( path );

    // @"BUILTINUsers"
    SecurityIdentifier sid = new SecurityIdentifier( WellKnownSidType.BuiltinUsersSid, null );

    FileSystemAccessRule ace = new FileSystemAccessRule( sid, FileSystemRights.FullControl, AccessControlType.Allow );

    DirectorySecurity acl = dirInfo.GetAccessControl();
    acl.AddAccessRule( ace );

    dirInfo.SetAccessControl( acl );

 

Technorati tags: , ,