\

Školení Návrhové vzory, OOP a UML


 Thursday, January 28, 2010
C# Posterous API pro Silverlight 4 (a .Net Framework 3.5) – verze 0.0.0.2

Stáhnout C# Posterous API pro Silverlight 4.0

Stáhnout C# Posterous API pro .Net Framework 3.5

Vše podstatné k C# Posterous API naleznete v úvodním článku.

Poznámky ke změnám v této verzi:

  • Kvůli verzi pro Silverlight přidány další asynchronní metody tak, aby bylo možné získat data z webu asynchronně, jak to Silverlight vyžaduje a jak je toto chování v aplikacích vynuceno  asynchronními metodami v rozhraní platformních tříd - příkladem budiž rozhraní tříd WebRequest a WebResponse. Pokud se pokusíte zavolat synchronní verzi metody v SL z UI vlákna, měli byste z Posterous API dostat výjimku – to je lepší varianta, než skončit v paralyzovaném stavu, kdy celá aplikace na nic nereaguje.

Ukázka uložení  změn v blogpostu – přidání komentáře. :


        var comment = post.CreateNewComment(updateText);
        post.SaveChangesCompleted += (_0, _1) =>
                                         {
                                             Assert.IsTrue(comment.Id > 0);
                                             TestComplete();
                                         };
        post.SaveChangesAsync();

  • V Silverlight verzi aplikace nedostanete v událostech rozhraní IRawRequestResponsePublisher k modifikaci objekty HttpWebRequest a HttpWebResponse, které jsou použity pro stažení obrázku autora (IAuthor.AuthorPicture) a stažení média (IPosterousMedium.Medium). Důvodem je, že pro stažení používám svého potomka třídy WebClient. Tento potomek přepisuje metody GetWebRequest a GetWebResponse, které jsou poté nabídnuty v událostech dostupných přes rozhraní IRawRequestResponsePublisher. V Silverlightu je ale třída WebClient označena jako kritický kód (Critical) a takzvaný transparentní  (Transparent) kód, pod který patří i námi psaný kód, nemá právo z takto označené infrastrukturní třídy podědit. Kromě dvou výše zmíněných omezení ale IRawRequestResponsePublisher pracuje stejně jako v desktopové verzi  a v další verzi API uvažuji, že místo WebClienta použiju na stažení obrázku autora i všech dalších médií přímo třídy WebRequest a WebResponse, které budou opět nabídnuty i v rozhraní IRawRequestResponsePublisher.
  • Silverlight má omezený přístup k souborovému systému, a proto naleznete v blogpostu (IPosterousPost) a twitter postu (ITwitterPost) další dvě metody pro přidání médií. Ve verzi 0.0.0.1 bylo možné předat pouze cestu k souboru, nyní můžete předat jakýkoli stream – např. Stream načtený z IsolatedFileStorage.
    Nové metody:
    void AppendMedium(Stream stream, string mediaName, Action<Stream> releaseStreamFunction);
    void AppendMedium(Stream stream, string mediaName);

Kromě streamu a názvu média můžete do jedné z variant funkce AppendMedium předat delegáta typu Action<Stream> , který bude vyvolán v okamžiku, kdy Posterous API  již se streamem nepotřebuje pracovat. Nejasná zodpovědnost, kdo vlastní a hlavně uvolňuje zdroje alokované objektem stream, mě právě vedla k tomu, že v první verzi API pro .Net Framework 3.5 jste mohli pouze předat název souboru a životní cyklus FileStreamu byl zcela pod mou kontrolu. Jestliže delegáta releaseStreamFunction nepředáte, máte životní cyklus streamu zcela ve svých všemocných rukou. Posterous API ani jeho autor si nepřejí být vyzváni na souboj  žádným šíleným omnipotentním vývojářem :-), a proto na předaném streamu Posterous API nikdy nevolá metodu Close ani Dispose.

Ukázka práce s metodou AppendMedium:

IPosterousPost newPost = site.CreatePost(DateTime.Now + " Media Silverlight",
                                                         "Príliš žlutoucký kun úpel dábelské ódy", true);

                IsolatedStorageFileStream stream = new IsolatedStorageFileStream("AlbumArtSmall.jpg ", FileMode.Open, IsolatedStorageFile.GetUserStoreForSite());
                
                newPost.AppendMedium(stream, "mojeSL.jpg", isoStream => isoStream.Close());
                               
                newPost.AddTag("Všechno a nic");
                newPost.AddTag("C# omnia vincit");
                newPost.SaveChangesCompleted += (_, __) =>
                                            {
                                                Assert.IsTrue(newPost.Id > 0);
                                                TestComplete();
                                            };
                newPost.SaveChangesAsync();

Jednoduchá ukázka použití API v Silverlightu. V jednoduchém boxu na stránce zobrazíme titulek spotu a url spotu. Výsledek vypadá takto:

SLBox

 

Ve Visual Studiu jsem založil projekt typu běžná navigační aplikace v Silverlightu. Zde je jednoduchý “ViewModel” pro stránku:

public class VM_Posts : INotifyPropertyChanged
    {
        public static readonly string ASYNC_EXCEPTION_TEXT = "Error while retrieving data. See inner exceptions for details";
        
        private bool m_isBusy;
        private IEnumerable<ViewPost> m_posts;

        public VM_Posts()
        {
            m_posts = null;
            IsBusy = false;
            LinkClickCommand = new DelegateCommand<String>(link => Debug.WriteLine(link) /*m_navigationServices.HandleExternalLink(link)*/,
                                                             _ => true);
            init();
        }

        
        private void init()
        {

                IsBusy = true;
                IPosterousApplication posterousApp = PosterousApplication.Current;
                IPosterousAccount posterousAccount = posterousApp.GetPosterousAccount("<PosterousUserName>", "PosterousPassword>");

                posterousAccount.SitesLoaded += (o, e) =>
                                                    {
                                                        throwIfAsyncEx(e.Exception);
                                                        posterousAccount.PrimarySite.PostsLoaded += (_, e2) =>
                                                                                                        {
                                                                                                            throwIfAsyncEx(e2.Exception);
                                                                                                            Posts = (from p in e2.Value
                                                                                                                    select new ViewPost
                                                                                                                               {
                                                                                                                                   Title = p.Title,
                                                                                                                                   Body = p.Body,
                                                                                                                                   Url = p.Url

                                                                                                                               }).ToList();                                                                                                            
                                                                                                            
                                                                                                        };
                                                        posterousAccount.PrimarySite.LoadAllPostsAsync();
                                                    };



                posterousAccount.LoadSitesAsync();
            
            
        }

       private void throwIfAsyncEx(Exception exception)
        {
            if (exception != null)
            {
                IsBusy = false;
                throw new Exception(ASYNC_EXCEPTION_TEXT,exception);
            }
        }
        
        

        public IEnumerable<ViewPost> Posts
        {
            get
            {
                return m_posts;
            }
            private set
            {
                
                m_posts = value;
                if (m_posts != null)
                {
                    IsBusy = false;
                }
                OnPropertyChanged(new PropertyChangedEventArgs("Posts"));
                
                
            }
        }

        

        public bool IsBusy
        {
            get
            {
                return  m_isBusy;
            }
            private set
            {
                m_isBusy = value;
                OnPropertyChanged(new PropertyChangedEventArgs("IsBusy"));
            }
        }

        public ICommand LinkClickCommand
        {
            get;
            private set;
        }

        #region Implementation of INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion
    }

    public class ViewPost
    {
        public string Title
        {
            get;
            set;
        }

        public string Body
        {
            get;
            set;
        }
        

        public string Url
        {
            get;
            set;            
        }
    }
}

V privátní metodě init, která je volána ihned po vytvoření instance třídy WM_Posts, nahrajeme blogy (Sites –> metoda LoadSitesAsync) a poté opět asynchronně z primárního blogu (PrimarySite) nahraju všechny blogposty (metoda LoadAllPostsAsync). Jestliže při některém asynchronním volání dojde k výjimce, metoda throwIfAsyncEx výjimku zpropaguje do UI vlákna.

Z nahraných blogpostů jsou vlastností Title, Url a Body přeneseny do instancí pomocné třídy ViewPost a kolekce objektů ViewPost je uložena do vlastnosti Posts. Třídu ViewPost vytvořit musíme, protože “Binding” dat, který budeme používat v XAMLu, nedokáže v Silverlightu z bezpečnostních důvodů pře reflection přistupovat ke člelnům “internal” třídy deklarované v jiné assembly. Třída PosterousPost, která v Posterous API implementuje rozhraní IPosterousPost, je označena jako internal. Ze stejného důvodu v Silverlightu nemohu použít místo explicitně definované třídy ViewPost anonymní datový typ – i anonymní datové typy jsou reprezentovány ve výsledném aplikačním dll třídami s modifikátorem viditelnosti “internal” a kód pro “binding” dat je ve zcela jiné platformní assembly.

Kromě vlastnosti Posts nabízí třída WM_Posts vlastnost IsBusy, kterou v XAMLu  využijeme k zobrazení indikátoru informujícího uživatele, že právě získáváme data. Vystaven je také LinkClickCommand, který nůže být zavolán například v okamžiku, kdy je stisknuto nějaké tlačítko reprezentující hyperlink s URL blogpostu.

A zde je pro úplnost ještě XAML. Památeční XAML, protože mi při jeho psaní nejméně a bez jakékoli nadsázky 50x spadlo Visual Studio 2010 Beta 2 (s Resharperem).:-)

<navigation:Page x:Class="SL_PosterousAPITest.Home"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
    xmlns:ct="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    xmlns:local="clr-namespace:SL_PosterousAPITest;assembly=SL_PosterousAPITest"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
    Title="Home"
    Style="{StaticResource PageStyle}">

    <Grid x:Name="LayoutRoot">
        <Grid.Resources>
            <local:VM_Posts x:Key="PostsView"></local:VM_Posts>            
            <Style x:Name="PostTitleStyle" TargetType="TextBlock">
                <Setter Property="FontWeight" Value="Bold" />
                 <Setter Property="Foreground" Value="IndianRed" />
                <Setter Property="FontSize" Value="14" />
            </Style>
            <Style x:Key="PostsRectangle" TargetType="Rectangle">
                <Setter Property="RadiusX" Value="30" />
                <Setter Property="RadiusY" Value="30" />                
                <Setter Property="Fill">
                    <Setter.Value>
                        <LinearGradientBrush>
                            <GradientStop Offset="0" Color="LightYellow" />
                            <GradientStop Offset="1" Color="LightBlue" />                            
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style TargetType="ItemsControl">
                <Setter Property="Width" Value="500" />
                <Setter Property="Height" Value="360" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <ScrollViewer BorderThickness="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                                <Grid>                                    
                                    <Rectangle Style="{StaticResource PostsRectangle}">                                        
                                    </Rectangle>
                                    <ItemsPresenter Margin="15,15,0,0"/>
                                    <ct:BusyIndicator IsBusy="{Binding Path=IsBusy}" 
                                                      DisplayAfter="0" 
                                                      HorizontalAlignment="Center" 
                                                      VerticalAlignment="Center"                                                       
                                                      />
                                    
                                    
                                </Grid>
                            </ScrollViewer>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>        
        <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}">

            <StackPanel x:Name="ContentStackPanel" DataContext="{StaticResource PostsView}">

                <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}"
                                   Text="Home"/>
                <ItemsControl Name="itemsPosts" ItemsSource="{Binding Mode=OneWay, Path=Posts}">                  
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Vertical">
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Style="{StaticResource PostTitleStyle}" Text="{Binding Path=Title}"></TextBlock>                                
                                 </StackPanel>
                                <HyperlinkButton Content="{Binding Path=Url}" 
                                                 Command="{Binding Source={StaticResource PostsView}, Path=LinkClickCommand}"                                                  
                                                 CommandParameter="{Binding  RelativeSource={RelativeSource Self}, Path=Content}"
                                                 FontSize="12"
                                                 ></HyperlinkButton>                                
                            </StackPanel>
                        </DataTemplate>                        
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </StackPanel>

        </ScrollViewer>
    </Grid>

</navigation:Page>

Share/Save/Bookmark Thursday, January 28, 2010 4:33:08 PM (Central Europe Standard Time, UTC+01:00)  #     
Comments [0]  .NET Framework | C# Posterous API | Silverlight


 Friday, January 15, 2010
Projekt C# Posterous API – verze 0.0.0.1 Alfa

 

Stáhnout knihovnu – download

Jak jsem avizoval minulý týden na twitteru, píšu C# wrapper webového API zajímavé služby Posterous.

Pár odkazů na začátek:

Jestliže nevíte, co je Posterous, přečtěte si článek na Živě.

Popis Posterous API. Hned na začátku zdůrazním, že autoři Posterous API nepovažují API za kompletní a za sebe dodám, že je to na mnoha místech vidět.:)

Několik důležitých informací:

  1. Projekt musí být stažen z mých stránek, jakékoli vystavování knihovny na jiném webu a serveru je zakázáno.
  2. Knihovnu jako celek v této verzi můžete používat dle libosti na komerčních i nekomerčních projektech. Zakázáno je samozřejmě vydávání knihovny za vlastní, její dekompilace a použití jen části knihovny.:) Jako autor knihovny nic negarantuji, nezodpovídám za případné přímé ani nepřímé škody vzniklé použitím knihovny a na opravu chyb knihovny není žádný nárok. Chyby lze reportovat na emailovou adresu PosterousAPI@renestein.net.
  3. Teprve dnes padlo rozhodnutí, že API v kódu musejí být komentovány v češtině. API zatím komentováno není a tento spot by vám měl pomoci se v knihovně zorientovat. Posterous API je součástí většího projektu. Posterous jsem si vymyslel a přidal do projektu sám a i když jsme s partnerem dohodnuti, že s Posterous knihovnou si mohu dělat, co chci, dokumentace musí být v češtině – stejně jako zbytek projektu. Pokusím se ale připravit i EN dokumentaci.
  4. Knihovna je zkompilována ve VS 2010 BETA 2 pro .Net Framework 3.5. Chci připravit i verze pro Compact .Net framework a Silverlight.

 

A nyní jž k samotnému API.

Branou k funkcím knihovny je třída PosterousApplication a její statická vlastnost Current.

Nejdříve se podíváme, jak pracovat s účtem Posterous. Metoda GetPosterousAccount vrací odkaz na objekt IPosterousAccount, který reprezentuje účet uživatele na službě Posterous.

using RStein.Posterous.API;
IPosterousAccount m_account = PosterousApplication.Current.GetPosterousAccount("posterousUserName", "posterousPassword");
  public interface IPosterousAccount : IExtensionInterface, IApplicationHolder
    {
        string Name { get; }
        IEnumerable<IPosterousSite> Sites { get; }
        void LoadSites();
        void LoadSitesAsync();
        event EventHandler<EventArgsValue<IEnumerable<IPosterousSite>>> SitesLoaded;
        IPosterousSite PrimarySite {get;}
        
    }

Nejzajímavější vlastností v rozhraní IPosterousAccount je vlastnost Sites, která obsahuje kolekci všech “blogů” uživatele. Kolekce Sites, stejně jako většina dalších vlastností a kolekcí i u jiných objektů, je naplněna daty až při prvním přístupu.

Jestliže chcete pracovat s výchozím blogem uživatele, můžete využít vlastnost IPosterousAccount.PrimarySite.

Rozhraní IPosterousSite

public interface IPosterousSite : IExtensionInterface
    {
        int Id { get; }
        string Name { get; }
        string Url { get; }
        bool IsPrivate { get; }
        bool IsPrimary{ get;}
        bool AreCommentsEnabled{ get; }
        IPosterousAccount PosterousAccount { get; set; }

        IEnumerable<IPosterousPost> Posts { get; }
        int TotalPosts { get; }
        int LoadedPosts { get; }
        void LoadAllPosts();
        void LoadAllPostsAsync();
        event EventHandler<EventArgsValue<IEnumerable<IPosterousPost>>> PostsLoaded;        

        IEnumerable<string> Tags { get; }
        bool IsTagsLoaded { get; }        
        void LoadTags();
        void LoadTagsAsync();
        event EventHandler<EventArgsValue<IEnumerable<string>>> TagsLoaded;
        
        IEnumerable<IPosterousPost> GetPostsByTag(string tag);
        void GetPostsByTagAsync(string tag);
        event EventHandler<EventArgsValue<IEnumerable<IPosterousPost>>> PostsByTagLoaded;

        IEnumerable<IPosterousPost> GetPostsInPage(int page, int recordsCount);
        void GetPostsInPageAsync(int page, int recordsCount);
        event EventHandler<EventArgsValue<IEnumerable<IPosterousPost>>> PostsInPageLoaded;

        IPosterousPost CreatePost(string title, string body, bool autopostAll);

        
    }

Každý blog (IPosterousSite) obsahuje blogspoty  - objekty podporující rozhraní IPosterousPost.

Assert.IsTrue(m_account.PrimarySite.Posts.Count() > 0); 
 public interface IPosterousPost : IEntityWithClientState
    {
        string Link { get; }
        string Title{ get; set; }        
        string Url { get; }
        int Id { get;}
        string Body {get; set;}                    
        DateTime PostDate { get; }
        int Views { get; }
        bool Private { get; }
        IAuthor Author { get; }
        bool AreCommentsEnabled { get; }                
        IPosterousComment CreateNewComment(string commentBody);
        void AppendMedium(string filePath);        
        IEnumerable<IPosterousComment> Comments { get; }
        IEnumerable<IPosterousMedium> Media { get; }
        IEnumerable<String> Tags{ get; }
        void AddTag(string tag);
        IPosterousSite Site { get; }
        void Refresh();
        
    }

Při přístupu k vlastnosti Posts jsou staženy všechny blogspoty v dávkách po 50 položkách. 50 položek najendou je interní omezení Posterous API. Jestliže nechcete nahrávat všechny blogspoty, můžete sami “stránkovat” a nahrávat blogspoty pomocí metody GetPostsIn Page.

//Nahraje z první stránky dva blogspoty
var posts = m_account.Sites.First().GetPostsInPage(1, 2);

Můžete také nahrát pouze blogspoty označené vybraným tagem. Seznam dostupných tagů zjistíte ve vlastnosti IPosterousSite.Tags. Dle mých zkušeností ale vrácení blogpostů nefunguje v Posterous API zcela správně a občas blogposty vráceny nejsou.

//Vrátí se blogposty označené tagem "Všechno a nic"
var posts = m_account.Sites.First().GetPostsByTag("Všechno a nic");

 

Kromě dalších zajímavých a samopopisných informací v každém blogspotu naleznete i kolekci komentářů k blogspotu (rozhraní IPosterousComment) a informaci o přiložených souborech (audio, foto, mp3… – rozhraní IPosterousMedium ) .

public interface IPosterousComment : IExtensionInterface 
    {
        int Id {get;}
        IAuthor Author {get;}
        DateTime CreateDate {get;}        
        string Body {get;}        
        IPosterousPost Post{get;}
        
        
    }
 public interface IPosterousMedium : IExtensionInterface
    {
        MediumType Type { get;}
        string Url { get;  }
        Stream Content { get; }
        int FileSize { get; }
        IDictionary<string, object> ExtendedInfo { get; }
        bool IsContentLoaded { get;}
        void LoadContent();
        void LoadContentAsync();   
        event EventHandler<EventArgs> ContentLoaded;
    }
 

U médií se vlastnost Content opět naplní až při přístupu a jakékoli další informace o médiích stažené z Posterous naleznete v kolekci ExtendedInfo – např. informace o náhledu obrázku.

Nové blogspoty je samozřejmě možné vytvářet i s médii.

//Nový post, první argument – titulek blogspotu, druhý argument tělo blogspotu, 
//třetí argument - pokud je true dojde automaticky k rozeslání postu na všechny další registrované služby -//(Twitter, FB...)
IPosterousPost newPost = m_account.PrimarySite.CreatePost("Obrázek HUDBA TeST",
                                                "Příliš žluťoučký kůň úpěl ďábelské ódy", true);

//Přidání obrázku
            newPost.AppendMedium(@"c:\Users\STEIN\Documents\Hudba\Once\AlbumArtSmall.jpg");
//Přidání mp3
            newPost.AppendMedium(@"c:\Users\STEIN\Documents\Hudba\Once\01_falling_slowly.mp3");
//Uložení postu na server
            newPost.SaveChanges();

Posterous bohužel nevrací po uložení automaticky veškeré informace o novém spotu (informace o médiích apod.), takže jsem zvolil mechanismus, kdy po volání SaveChanges je vždy ještě volána metoda Refresh, která přes další (Bit.Ly) API dotáhne podrobnosti, aby programátor nemusel na získání dodatečných údajů myslet a volat metodu Refresh sám.

Metodu Refresh ale samozřejmě sami volat můžete a získate tak vždy aktuální data ze serveru.

Uložený blogspot můžete editovat – ne všechny údaje lze nyní uložit na server, podívejte se na současný stav web API.

string updateText = "Updated " + DateTime.Now.ToString();
            post.AppendMedium(@"c:\Users\STEIN\Documents\Hudba\Dylan Bob - Time Out Of Mind\AlbumArt_{6DF0A444-4F68-489B-AFCF-A985B02166BB}_Large.jpg" );
            post.Body = updateText;
            post.Title = updateText;
            post.SaveChanges();

K uloženému blogspotu můžete přidávat nové komentáře.

var comment = post.CreateNewComment(updateText);            
            post.SaveChanges();
  

Posterous API dovoluje vytvořit zjednodušený nový blogpost, aniž byste museli mít na Posterous účet. K publikaci vám stačí předat jméno a heslo stávajícího twitter účtu.  Url nového blogspotu automaticky publikuje na twitter. Jestliže máte Posterous účet svázaný s twitter účtem, blogspot se uloží na vašem primárním blogu (Site). Toto API se hodí hlavně pro rychlou publikaci obrázků na twitter a  Posterous toto API považuje za alternativu ke službě TwitPic.

Nejprve opět přes vstupní objekt PosterousApplication získáte twitter účet (rozhraní ITwitterAccount) .

m_twitterAccount = PosterousApplication.Current.GetTwitterAccount("twitter_name", "twitter_password");
    public interface ITwitterAccount : IApplicationHolder
    {
        string UserName{ get; }
        ITwitterPost CreatePost(string title, string body, bool postToTwitter);        
    }
 

A takto vypadá rychlá publikace obrázku

//Nový post, první argument – titulek blogspotu, druhý argument - tělo blogspotu, třetí argument – pokud je true, automaticky dojde k publikaci url obrázku (blogspotu) na twitter.
ITwitterPost newPost = m_twitterAccount.CreatePost(null,
                                                               null, true); 

            newPost.AppendMedium(“c:\pic.jpg”);
            newPost.SaveChanges();
 

Rozhraní ITwitterPost.

public interface ITwitterPost : IEntityWithClientState
    {
        string Url { get; }
        string Title{ get; }
        string Body { get; }
        string MediaId { get; }
        void AppendMedium(string filePath);
        bool AutopostToTwitter { get; }
        ITwitterAccount TwitterAccount { get; }
        IEnumerable<String> MediaNames { get; }
        ISinglePostInfo GetPostInfo();
    }

Další API vám dovoluje získat informace o libovolném blogpostu, u kterého znáte Bit.ly  adresu – Bit.Ly adresa je každému blogpostu přiřazena při vytvoření  - vlastnost IPosterousPost.Url.

Tento blogpost nemusí pocházet z vašeho blogu (Site).

Opět přes objekt PosterousApplication získáte odkaz na IBitLyService.

 public interface IBitLyService : IApplicationHolder
    {
        ISinglePostInfo GetSinglePost(string bitLySuffix);
        void GetSinglePostAsync(string bitLySuffix);
        event EventHandler<EventArgsValue<ISinglePostInfo>>  SinglePostLoaded;
    }
 
Ukázka získání jednoduchého blogspotu z této služby.
Uri uri = new Uri(Url);
//Extenzní metoda GetBitLySuffix pro snadné získání suffixu
ISinglePostInfo post = bitLyService.GetSinglePost(uri.GetBitLySuffix())
 

Rozhraní ISinglePostInfo

 public interface ISinglePostInfo : IExtensionInterface
    {
        string Link { get; }
        string Title{get;}        
        string Url { get; }
        int Id { get;}
        string Body{get;}                    
        DateTime PostDate {get;}
        int Views { get; }
        bool Private { get; }
        IAuthor Author { get; }
        bool AreCommentsEnabled { get; }                        
        IEnumerable<IPosterousComment> Comments { get;}
        IEnumerable<IPosterousMedium> Media { get;}
        IEnumerable<String> Tags{ get;}        
    }
 

Pokročilejší nastavení, která by se vám mohla hodit.

Blogspoty mohou být označeny jménem aplikace, která je vytvořila, a odkazem na aplikaci.

PosterousApplication.Current.ApplicationName = "Moje cool aplikace";
PosterousApplication.Current.ApplicationUrl = http://renestein.net;

Chcete pracovat přímo s objekty HttpWebRequest a HttpWebResponse? Potřebujete doplnit autentizaci k proxy, nebo chcete změnit maximální dobu, po kterou bude trvat požadavek? S pomocí rozhraní IRawRequestResponsePublisher  je to jednoduché.

    public interface IRawRequestResponsePublisher : IExtensionInterface
    {
        event EventHandler<EventArgsValue<WebRequest>> WebRequestCreated;
        event EventHandler<EventArgsValue<WebResponse>> WebResponseCreated;
    }
 

Stačí zaregistrovat obslužné metody pro události a poté všechny objekty HttpWebRequest a HttpWebResponse, které interně knihovna používá,  můžete upravit dle libosti.

Ukázka změny vlastnosti Timeout.

IRawRequestResponsePublisher publisher =
                PosterousApplication.Current.GetInterface<IRawRequestResponsePublisher>();

            Debug.Assert(publisher != null);
            publisher.WebRequestCreated += ((_, e) => e.Value.Timeout = WEB_TIMEOUT);

C# Posterous API toho zvládne ještě více, ale myslím, že pro dnešek už bylo kódu dost. Užijte si to. :-)


Share/Save/Bookmark Friday, January 15, 2010 5:49:51 PM (Central Europe Standard Time, UTC+01:00)  #     
Comments [1]  .NET Framework | C# Posterous API | Compact .Net Framework | Silverlight


 Tuesday, June 09, 2009
Chyba při používání prvku Popup v Silverlightu 2.0

Tento spot se objevil již před nějakou dobou jako komentář na Zdrojáku, ale protože se s podobným problémem setkal i Michal Kočí na Twitteru, dostal jsem pár emailů s popisem chyby v Silverlightu a znovu jsme narazili na podobné chyby při portaci firemního frameworku, dávám původní komentář i sem na na blog, abych měl kam trvale odkazovat další zoufalce. :)

Jestliže máte vlastni User Control, ve kterém je Popup a tento Popup neobsahuje ListBox (a možná další prvky), je možné Popup zobrazit a používat, aniž by byl přidán do kolekce Children rodičovské “stránky” (třída typicky nazvaná Page  – potomek UserControl) v Silverlightu. Takto definovaný POPUP funguje bez problémů.

<pexeso:popupbase x:class="RStein.Pexeso.SaveFile" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:pexeso="clr-namespace:RStein.Pexeso">

    <grid x:name="LayoutRoot" background="Black">

        <popup name="filesPopup">

            <popup.child>

                <stackpanel orientation="Vertical" background="Red">

                    <textblock text="Název souboru s uloženou hrou" fontsize="15" margin="5,5,5,0" horizontalalignment="Left" foreground="White" textdecorations="Underline"></textblock>

                    <stackpanel orientation="Horizontal">

                        <textbox name="txtFile" margin="5" minwidth="200"></textbox>

                        <textblock foreground="Yellow" visibility="Collapsed" name="txtError" text="Musíte zadat platný název souboru!" horizontalalignment="Left" verticalalignment="Center" fontweight="Bold" fontsize="10"></textblock>

                    </stackpanel>

                    <stackpanel orientation="Horizontal" margin="5">

                        <button style="{StaticResource DialogButton}" content="Uložit" name="btnSelect" click="btnSelect_Click"></button>

                        <button style="{StaticResource DialogButton}" content="Zpět" name="btnBack" click="btnCancel_Click"></button>

                    </stackpanel>

                </stackpanel>

            </popup.child>

        </popup>

    </grid>

</pexeso:popupbase>

 

Jestliže ale Popup obsahuje Listbox (a pravděpodobně i jiné prvky), Popup se zobrazí, ale při vybrání libovolné položky v ListBoxu celý Silverlight plugin spadne do obsluhy události UnhandledException a napíše jen něco o interní fatální chybě. Mimochodem, Bety a RC Silverlightu tímto problémem podle mě netrpěly.

Tento popup způsobí pád Silverlightu, jestliže popup není před svým zobrazením přidán do kolekce Children.

<pexeso:popupbase x:class="RStein.Pexeso.SelectFile" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:pexeso="clr-namespace:RStein.Pexeso">

    <grid x:name="LayoutRoot" background="Black">

        <popup name="filesPopup">

            <popup.child>

                <stackpanel orientation="Vertical" background="Red">

                    <textblock text="Vyberte uloženou hru" fontsize="15" margin="5,5,5,0" horizontalalignment="Left" foreground="White" textdecorations="Underline"></textblock>

                    <textblock foreground="Yellow" visibility="Collapsed" fontsize="10" name="txtError"></textblock>

                    <border cornerradius="20" background="White">

                        <listbox name="lstFiles" background="Orange" height="200">

                            <listbox.itemtemplate>

                                <datatemplate>

                                    <textblock text="{Binding Mode=OneWay}" foreground="White"></textblock>

                                </datatemplate>

                            </listbox.itemtemplate>

                        </listbox>

                    </border>

                    <stackpanel orientation="Horizontal">

                        <button style="{StaticResource DialogButton}" content="Vybrat soubor" name="btnSelect" click="btnSelect_Click"></button>

                        <button style="{StaticResource DialogButton}" content="Zpět" name="btnBack" click="btnCancel_Click"></button>

                    </stackpanel>

                </stackpanel>

            </popup.child>

        </popup>

    </grid>

</pexeso:popupbase>

 

Před zobrazením Popupu tedy musíme vždy přidat Popup do kolekce Children a po uzavřeni Popupu jej případně odebrat.


 

 private void btnLoad_Click(object sender, RoutedEventArgs e)

        {

            SelectFile file = new SelectFile();

            var files = FileAccessComponent.Instance.GetRootFiles();

            if (files.Length == 1)

            {

                return;

            }

 

            file.FileListBox.ItemsSource = files;           

 

            LayoutRoot.Children.Add(file); //Přidat do kolekce

 

            file.DialogClosed += file_DialogClosed; //Vlastní událost pro všechny mé dialogy

            showPopup(file.FilesPopup);

            file.FileListBox.Focus();

        }

 

        void file_DialogClosed(object sender, EventArgs e)

        {

            SelectFile sfDialog = sender as SelectFile;

 

            try

            {

                if (sfDialog.LastResult == DialogResult.OK && sfDialog.FileListBox.SelectedItem != null)

                {

                    m_currentGame = PexesoGame.Load(sfDialog.FileListBox.SelectedItem.ToString());

                    removeButtons();

                    rebindGameData();

                }

            }

            catch (Exception e1)

            {

                Console.WriteLine(e1);

            }

            finally

            {

                LayoutRoot.Children.Remove(sfDialog); //Odebrat z kolekce

                sfDialog.DialogClosed -= saveFileDialog_DialogClosed;

                hidePopup(sfDialog.FilesPopup);

            }

 

        }


Share/Save/Bookmark Tuesday, June 09, 2009 9:51:20 AM (Central Europe Standard Time, UTC+01:00)  #     
Comments [0]  Silverlight