Quantcast
Channel: Development With A Dot
Viewing all 404 articles
Browse latest View live

ASP.NET Formatted String Control

$
0
0

Back to ASP.NET Web Forms land! SharePoint includes a handy control, FormattedString, that can be used to render the contents of its child controls as specified in a format string; pretty much what String.Format does. I wanted to do the same with plain old ASP.NET Web Forms, and here’s what I came up with:

[ParseChildren(false)]
[PersistChildren(true)]
[ControlBuilder(typeof(FormattedControlControlBuilder))]
publicclass FormattedControl : Control
{
public String FormatString { get; set; }
 
protectedoverridevoid RenderChildren(HtmlTextWriter writer)
    {
if (String.IsNullOrWhiteSpace(this.FormatString) == false)
        {
            var list = new List<String>();
            var builder = new StringBuilder();
            var sw = new StringWriter(builder);
            var hw = new HtmlTextWriter(sw);
 
foreach (var control inthis.Controls.OfType<Control>())
            {
                control.RenderControl(hw);
 
                list.Add(builder.ToString());
 
                builder.Clear();
            }
 
            writer.Write(this.FormatString, list.ToArray());
        }
else
        {
base.RenderChildren(writer);
        }
    }
}
 
publicclass FormattedControlControlBuilder : ControlBuilder
{
publicoverride Boolean AllowWhitespaceLiterals()
    {
returnfalse;
    }    
}

Key points are:

  • FormattedControl will not render as default, instead, it will capture the output of all of its child controls into a list and pass it as a parameter to the FormatString string, as {0}, {1}, etc;
  • ParseChildrenAttribute and PersisteChildrenAttribute are used to tell ASP.NET how to treat the controls declared inside FormattedControl;
  • The ControlBuilderAttribute is used to declare a custom control builder; this custom builder just tells ASP.NET to ignore whitespaces inside the control’s tag, otherwise, we would get a LiteralControl for each tab / space / return character present inside the FormattedControl’s tag, together with those controls explicitly declared.

An example:

<my:FormattedControlrunat="server"FormatString="{1}, {0}!">
<asp:Literalrunat="server"Text="World"/>
<asp:Literalrunat="server"Text="Hello"/>
</my:FormattedControl>

Of course, you should only use FormattedControl with controls that return string literals, otherwise, you will probably get a lot of garbage in the output.


Windows Live Writer Tricks

$
0
0

As many others, I use Windows Live Writer (WLW) as my main tool for blogging. It has aged a bit over the years and sometimes crashes, but I think it is still the best tool around for this purpose. It will only get better if Scott Hanselman (@shanselman) succeeds in releasing it as open source! Winking smile

I would like to share with you some of my favorite tips for getting the best out of it.

  1. Change default style and template:
    Navigate to %ProgramFiles(x86)%\Windows Live\Writer\template and change the files defaultstyle.css and default.htm. New posts will inherit these.
  2. Change IE version used for rendering posts:
    Set the desired Internet Explorer version through the Registry: go to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION and add key WindowsLiveWriter.exe with a value of (DWORD) 10000 (for IE10) or 11000 (IE11). Now you can preview HTML5 features right on WLW.
  3. Change posts location:
    This is useful if you use several machines and you want to keep all your posts (drafts, published) in the cloud (OneDrive, DropBox, Google Drive, etc). In Registry, go to HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows Live\Writer and add key Posts Directory. The value must be a full path!
  4. Export settings:
    Export all WLW settings by exporting this Registry key (and everything below): HKEY_CURRENT_USER\Software\Microsoft\Windows Live\Writer\Weblogs.
  5. Clearing cached themes:
    If you run into problems with a site’s theme, clear its local cache. Cached CSS and image files are stored at %AppData%\Windows Live Writer\blogtemplates.
  6. Disabling blog theme:
    If your theme misbehaves, and clearing the local cache doesn’t help, you can disable it in the ribbon:
    image
  7. Use the Windows Live Writer SDK:
    Create plugins for WLW in .NET. Download the SDK here and reference it from %ProgramFiles(x86)%\Windows Live\Writer. There are several examples out there, just check out this one.
  8. Log file:
    The log file and a couple of others are located here: %LOCALAPPDATA%\Windows Live Writer.
  9. Open old posts:
    If you need to open a post that you created a long time ago and it no longer shows in the recent posts list, what to do? Get the WLV Post Download plugin from http://aovestdipaperino.com/pages/wlw-post-download-plugin-instructions.aspx. After you have it, open a blog post in your browser with the WLW protocol. For example, to use it with an Orchard or Wordpress blog (MetaWeblog API), use this format: wlw://blog?postid=id, where you first need to find out the post id; with other blogs, use the format: wlw://blog/page.aspx. This will open up WLW with the desired post, and you can now change it and publish it.
  10. Use Blog This for blogging over a web page:
    In Internet Explorer, WLW adds an option for adding a link to the current page in a new blog post. It is called Blog This in Windows Live Writer and is available in the Tools menu:
    image
  11. Use plugins:
    WLW has lots of plugins available on the Internet. My favorites are:
  • Use the source:
    When you can’t easily format your text the way you want it using the designer (Edit) tab, you can switch to the Source tab and make your changes there. WLW will synchronize the designer.
  • Post drafts to your blog:
    imageAfter you save the draft, it won’t be visible to the World, you need to use your blog’s management console to actually publish it.
  • Get to know other WLW options:
    In FileOptions, explore what WLW offers (save auto recovery information, show word count in real time, disable emoticons, remember to add tags, check spelling, etc):

    image
  • Lesser-Known NHibernate Features: Dynamic Components

    $
    0
    0

    NHibernate, unlike others, has lots of ways to map columns from the database to and from classes. Normally, there is a 1:1 relation between columns and properties, but it doesn’t have to be so: there are, for example, components and dynamic components.

    This time we will be looking at dynamic components. Dynamic components allow the usage of a dictionary, where one or several columns from the database will be stored, each in its own entry. This is pretty cool, if we need to add more columns at some point, and we do not want, or can, change the class!

    Show me the code, I hear you say:

    publicclass DataStore
    {
    public DataStore()
        {
    this.Data = new Dictionary<String, Object>();
        }
     
    publicvirtualint Id { get; set; }
     
    publicvirtual IDictionary Data { get; set; }
    }

    Yes, it will be possible to use generic dictionaries (IDictionary<TKey, TValue>), when pull request for NH-3670 is merged, which should happen soon (NHibernate 4.1).

    Now, the mappings:

    var mapper = new ConventionModelMapper();
    mapper.Class<DataStore>(x =>
        {
            x.Id(y => y.Id, y => { });
            x.Component(y => y.Data, new
            {
                A = 0,
                B = ""
            }, y =>
            {
                y.Property(z => z.A);
                y.Property(z => z.B);
            });
        });

    I am setting the template for whatever will be stored in the Data dictionary, in this case, an integer column (A) and a string one (B) as an anonymous object. In NHibernate 4.1, it will be possible to use a dictionary instead (see NH-3704), which will help in making it more dynamic. In the third parameter to Component, we can change the mapping, for example, the physical properties of each column; we can even use ManyToOne instead of Property, so that a particular entry in the dictionary will point to another entity!

    A sample usage:

    session.Save(new DataStore { Data = new Dictionary<String, Object> { { "A", 1 }, { "B", "two" } } });

    SharePoint Reference Document Updated

    $
    0
    0

    Just updated my SharePoint reference document Excel (references: here and here) with the default content placeholders.

    It now contains:

    • Fields: all the built-in SharePoint field types;
    • Content types;
    • List templates;
    • Site templates;
    • SPDataSource returned fields;
    • List fields;
    • Document library fields;
    • Search content classes;
    • Content placeholders in default master pages.

    If you have any corrections or if I missed something, please let me know!

    Lesser-Known NHibernate Features: Statistics

    $
    0
    0

    NHibernate makes available a number of statistics about its work; this includes, among others:

    • All of the queries executed;
    • Number of entities loaded, inserted, updated and deleted;
    • Number of optimistic concurrency misses;
    • Number of second level cache hits and misses;
    • Number of transactions started and committed;
    • Number of connections opened and closed;
    • etc.

    This is available per session factory:

    var statistics = sessionFactory.Statistics;

    And all of these settings can be filtered per entity:

    var entityStatistics = sessionFactory.Statistics.GetEntityStatistics("MyEntity");

    Statistics can help us diagnose, for example, second level or query cache issues.

    If we have no need for them, we can disable them before building the session factory:

    cfg.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, Boolean.FalseString);

    Or at runtime:

    sessionFactory.Statistics.IsStatisticsEnabled = false;

    An advice: do switch it off while on production, it does have an effect on performance.

    NHibernate Pitfalls: Sharing a Session in Multiple Threads

    $
    0
    0

    The NHibernate ISession is not thread-safe, that is, it shouldn’t be shared by multiple threads. The ISessionFactory, however, is thread-safe, and thus it should be used to create ISession instances as needed. Do not worry, creating sessions does not mean that connections to the database are immediately open and kept alive, the ISession implementation only opens database connections when they are necessary and closes them when they cease to be.

    Open Source @ Microsoft

    $
    0
    0

    Introduction

    This post is based on the presentation I did for Porto Tech Hub 2015, Microsoft ♥ Open Source, slightly revised and augmented.

    TL;DR

    I intent to demonstrate that Microsoft’s involvement with open source is not exactly new.

    So, the big news is:

    • Microsoft is embracing/supporting/producing/using open source software: Microsoft& Open Source Software!
    • Lots of APIs are now open source, others will follow!
    • Applications are being considered for release as open source!

    But, let’s think for a moment… is this actually new?

    A Bit of History

    So, let’s take a walk down the memory lane and remember some of Microsoft’s positions on this subject…

    2001

    Hmmm… this doesn’t seem good for open source, does it?


    2005

    First version!


    2006

    Nice! At the time, AJAX Control Toolkit offered some cool features that would integrate nicely with ASP.NET!


    2007

    Open Office XML formats!


    2009

    Interesting! Who would have thought? Microsoft was then the 17th top contributor to the Linux kernel, even for “selfish” reasons – they wanted to be able to run Linux inside virtual machines, and also that Linux could run Windows VMs.


    2010

    Oxite was an attempt at building an open source CMS, which was discontinued. Eventually, some of the people involved moved to Orchard. Nice to see that VS includes jQuery and Modernizr in their ASP.NET templates!


    2012

    Wow, this this is getting interesting! All of MVC, Web API and related stuff is now open source! It seems they are getting serious about this!


    2013

    Visual Studio now has Git support!


    2014

    War is over! All peace! Winking smile


    2015

    Wow!!

    But Why?

    But why the big shift? Well, in my view, there are a couple of reasons:

    • Trust the source: companies will respect more a package if they can see what’s inside and even change it
    • Gain from community: attract respected developers from the open source communities; have others fix bugs and contribute new features
    • Build bridges: join communities with similar concerns together; we don’t always have to be competitors
    • Reach other markets: sell software to other platforms; profit from support instead as from licenses
    • Everybody else is doing it!

    What Exactly Are We Talking About?

    So, what is exactly Microsoft’s commitment to open source today? I’d say it’s down to:

    Standards

    Microsoft has submitted for standardization (unlike others who are generally considered more open source friendly). Some examples include:

    Not exactly open source, but they are also involved in the working groups that are specifying a number of technologies:

    Languages

    They have also build a couple of open source languages:

    And also support others in IIS and in tools such as Code and WebMatrix:

    Frameworks and Libraries

    Microsoft has made available a number of frameworks and libraries, including:

    A free implementation of Redis:

    It also contributed a number of libraries to existing projects:

    Visual Studio templates include popular open source JavaScript libraries:

    And IntelliSense is offered for a number of others:

    The next version of Visual Studio, 2015, will also support popular libraries for building JavaScript and managing dependencies, fully integrated with the IDE:

    Finally, the Microsoft Ajax Content Delivery Network makes available all of these and more: http://www.asp.net/ajax/cdn.

    Tools

    Also some great tools have been open sourced:

    Others were made freely available:

    Where Can I Find More Info?

    There are a number of Microsoft-sponsored locations:

    What’s Next?

    Microsoft – or, rather, some of its employees – have given glues on what might come next:

    • Windows Live Writer: the popular blog editor is probably going to be released as open source. Scott Hanselman has been championing this cause
    • Internet Explorer: there have been talks about open sourcing it, especially now that it is going to be replaced by Edge in Windows 10
    • Windows Phone and Windows: also possible, there have been rumors about it, but not quite substantiated, I’d say

    I would like to add a couple of suggestions myself:

    • SharePoint Designer: it is now freely available and has a number of notorious bugs; could profit from the community, because there is no other tool that does what it does
    • Expression Studio: the Expression suite has been discontinued and parts of it are present in Visual Studio 2013
    • Visual Studio Code: it is already based in an open source project (GitHubAtom)

    Conclusion

    So, as you can see, open source and Microsoft’s engagement is not exactly new. Microsoft has made important contributions to open source and appears to be willing to go even further. Not sure if Windows or Visual Studio themselves will ever be open source – I doubt it – but I think we will see an increasing push towards cross platform and open source solutions in the Microsoft ecosystem. These are interesting times indeed! Winking smile

    Entity Framework Pitfalls: Table Valued Functions

    $
    0
    0
    var customers3 = ctx.Database.SqlQuery(typeof(Customer), "SELECT * FROM [dbo].[GetCustomers]()");
    var customers3 = ctx.Database.SqlQuery(typeof(Customer), "SELECT * FROM [dbo].[GetCustomers]()");

    As of Entity Framework 6.x, Table Valued Functions are not supported, which is really a pity.

    For example, the following does not work:

    CREATEFUNCTION [dbo].[GetCustomers]()
    RETURNS @ReturnTable TABLE
    (
        Id INT,
        Email NVARCHAR(50),
        Phone NVARCHAR(50),
        Name NVARCHAR(50)
    )
    AS
    BEGIN
        INSERT @ReturnTable
    SELECT Id, Email, Phone, Name
    FROM dbo.Customer
    RETURN
    END

    And:

    //throws an exception complaining about TVF
    var customers1 = ctx.Database.SqlQuery(typeof(Customer), "[dbo].[GetCustomers]");
     
    //likewise
    var customers2 = ctx.Database.Customers.SqlQuery("[dbo].[GetCustomers]");

    However, you can do this:

    var customers3 = ctx.Database.SqlQuery(typeof(Customer), "SELECT * FROM [dbo].[GetCustomers]()");

    And it works!


    Sessão Netponto: Entity Framework 7

    $
    0
    0

    A minha apresentação sobre Entity Framework 7 feita na 6ª reunião presencial da Netponto em Coimbra está disponível aqui.

    Os tópicos cobertos foram:

    • Novidades do Entity Framework 7
    • Entity Framework 7 vs NHibernate

    Brevemente o video e a apresentação estarão disponíveis no site da Netponto.

    Obrigado a todos os que estiveram presentes! Winking smile

    SharePoint Pitfalls: Creating a Visual Studio Project Without SharePoint Locally Installed

    $
    0
    0

    This is the first on a (huge) collection of posts on SharePoint pitfalls. Hope you enjoy, and, please, do send me your feedback!

    If you do not have SharePoint locally installed, Visual Studio will not let you create a SharePoint project:

    sp-not-installed

    Fortunately, it is easy to go around this in two simple steps:

    1. Registry

      In the Registry, add the following key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\15.0\SharePoint

      In it, add two string values: Location=C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ and SharePoint=Installed

    2. Global Assembly Cache

      Copy the following assemblies from a machine where SharePoint is installed (C:\Windows\Microsoft.NET\GAC_32) into your development machine and add them to the GAC (gacutil):

      • Microsoft.SharePoint.dll
      • Microsoft.SharePoint.Client.dll
      • Microsoft.SharePoint.Client.Publishing.dll
      • Microsoft.SharePoint.Client.Runtime.dll
      • Microsoft.SharePoint.Client.ServerRuntime.dll
      • Microsoft.SharePoint.Library.dll
      • Microsoft.SharePoint.Linq.dll
      • Microsoft.SharePoint.Portal.dll
      • Microsoft.SharePoint.Publishing.dll

      Of course, you may need others as well.

    Enjoy!

    SharePoint Pitfalls: Save Publishing Site as Template Option Missing

    $
    0
    0

    If you want to save a publishing site as a template, so that it can be used to create other sites, you may find it surprising that the option is missing from the site settings page:

    image

    I don’t know exactly why, but publishing sites hide this option, however, it’s not difficult to get around it: just navigate to /_layouts/15/savetmpl.aspx. But, wait, what if you get this?

    image

    Easy, easy. Open your site in SharePoint Designer, click Site Options:

    image

    and change the value of property SaveSiteAsTemplateEnabled from false to true:

    image

    And now you will be able to access savetmpl.aspx and save your site.

    Farewell, ASP.NET Web Forms, We Hardly Knew Ye

    $
    0
    0

    ASP.NET Web Forms, the venerable web framework that Microsoft shipped with the .NET framework almost 15 years ago and we all hate love, is going away. Yes, it’s official: ASP.NET 5 will not include Web Forms, only MVC 6. ASP.NET 4.6, however, will still include Web Forms, including some updates, but the future appears to be all MVC (and OWIN, for that matter). Having spend a lot of my professional life working with Web Forms, I feel kind of sad. Yes, I do acknowledge event-hell, viewstate-hell, etc, but I find it easy to get around this once you know a thing or two. But what I really like about Web Forms is the reuse capacity that server-side controls offer: just add a reference to an assembly containing controls, register them in Web.config or in the page, and you’re done. A control encapsulates both client and server-side logic, so it is the perfect reusability mechanism for the web, in my opinion, and I wrote tens of posts on it. MVC now offers somewhat similar mechanisms, in the form of view components and tag helpers, but before that, there was really no reuse mechanism – partial views cannot be referenced from an assembly and helper methods cannot be extended. Don’t get me wrong: I like MVC, but I think that Web Forms was complementary. Taking in consideration the extensibility mechanisms offered by MVC, I can imagine that someone will even implement Web Forms on top of it! Winking smile

    Apart from Web Forms, ASP.NET 5 seems promising! I published recently an article on it for the portuguese magazine Programar, which you can find here. I may translate it to english and add a thing or two in the next couple of days, so stay tuned!

    Generating GDI+ Images for ASP.NET MVC Views

    $
    0
    0

    This post is about applying the same technique I presented for ASP.NET Web Forms, but this time for MVC.

    We need to have an ActionResult that does the actual work of converting whatever we draw in the Graphics context into an image with an inline Data URI. Here’s a possible solution, where you only specify the dimensions of the image to be generated:

    publicsealedclass InlineImageResult : ActionResult
    {
    privatereadonly Image bmp;
     
    public InlineImageResult(Int32 width, Int32 height)
        {
    //the PixelFormat argument is required if we want to have transparency
    this.bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
     
    this.Graphics = Graphics.FromImage(this.bmp);
    //for higher quality
    this.Graphics.CompositingQuality = CompositingQuality.HighQuality;
    this.Graphics.SmoothingMode = SmoothingMode.HighQuality;
    this.Graphics.InterpolationMode = InterpolationMode.High;
    //make the background transparent
    this.Graphics.Clear(Color.Transparent);
        }
     
    public Graphics Graphics { get; private set; }
     
    publicoverridevoid ExecuteResult(ControllerContext context)
        {
    using (this.bmp)
    using (this.Graphics)
    using (var stream = new MemoryStream())
            {
    //PNG because of transparency
                var format = ImageFormat.Png;
     
    this.bmp.Save(stream, format);
     
                var img = String.Format("<img src=\"data:image/{0};base64,{1}\"/>", format.ToString().ToLower(), Convert.ToBase64String(stream.ToArray()));
     
                context.HttpContext.Response.Write(img);
            }
        }
    }

    Now, we need to create an instance of this result and draw in it, in a controller’s action method:

    [ChildActionOnly]
    public ActionResult Image()
    {
        var result = new InlineImageResult(200, 50);
        result.Graphics.DrawString("Hello, World!", new Font("Verdana", 20, FontStyle.Regular, GraphicsUnit.Pixel), new SolidBrush(Color.Blue), 0, 0);
     
    return result;
    }

    Notice the ChildActionOnly attribute: it tells MVC that this action method is only meant to be used in child action (RenderAction) call, not as a stand-alone action, like this:

    <p>
        @{ Html.RenderAction("Image"); }
    </p>

    As you can see, this provides a very convenient way to generate images on the fly. You just need to learn about the drawing methods in GDI+.




    What’s New in C# 6.0

    $
    0
    0

    Introduction

    Visual Studio 2015 will be officially RTM on July 20th, Microsoft announced. With it comes a new version of the .NET framework (actually, two), .NET 5.0, and inside of it, support for a new version of the C# language, C# 6.0. Yeah, the numbers don’t match, keep that in mind! Winking smile

    If you are curious, Visual Studio 2015 will also include .NET 4.6. This will provide a migration path for those of us who are stuck with .NET 4.x code and can’t afford the breaking changes that .NET 5 will introduce. More on this in a future post.

    For the moment, I am going to talk about what’s new in C# 6.0, in no particular order. Some of you may be familiar with parts of it, and some might even be expecting a bit more, but unfortunately, some features that were previously announced didn’t make it to the final version.

    Parameterless Struct Constructors

    Unlike primary constructors, parameterless constructors for structures did make it. What’s new is, we no longer need to either define a constructor that takes values for all settable properties in a structure, we can build constructors that only take some (or none) parameters and call more complex ones. Consider the following example:

    publicstruct MyStruct
    {
    public MyStruct() : this("A", 1) {  }
     
    public MyStruct(string a, int b)
        {
    this.A = a;
    this.B = b;
        }
     
    publicstring A { get; set; }
    publicint B { get; set; }
    }

    This wouldn’t compile in .NET 4.x, with a message of “Structs cannot contain explicit parameterless constructors”. Yes, they can… now! Winking smile

    Auto-Property Initializers

    It is now possible to provide an initial value for auto-implemented properties without resorting to a custom constructor. Here’s how, in two examples:

    publicclass MyClass
    {
    publicint MyNumericProperty { get; set; } = 1;
    publicbool MyBooleanOtherProperty { get; set; } = (MyNumericProperty > 0);
    }

    Did you notice how we can even use simple expressions in the initialization block? Pretty cool!

    Getter-Only Auto-Properties

    Similar to the previous example, we can now have getter-only properties, that is, without any kind of setter. We just need to provide an initialization value:

    publicclass Math
    {
    publicstaticdouble PI { get; } = 3.14159265359;
    }

    Alternatively, we can define its value in a constructor:

    publicclass Math
    {
    publicstaticdouble PI { get; }
     
    static Math()
        {
            PI = 3.14159265359;
        }
    }

    Expression-Bodied Methods and Properties

    Not sure of the actual interest of this one, but, hey, it’s here: the ability to supply the body for properties and methods from simple expressions.

    publicclass MyClass
    {
    publicint Add(int a, int b) => a + b;
     
    publicstring TimeOfDay => DateTime.Now.TimeOfDay;
    }

    nameof Expressions

    nameof expressions avoid the need to hardcode names or use complex reflection or LINQ expression tricks. It’s better to show it in action:

    void ThrowArgumentNullExceptionUsingNameOf(string param1)
    {
    thrownew ArgumentNullException(nameof(param1));    //"param1"
    }
     
    var className = nameof(MyClass);                    //"MyClass"
     
    var propertyName = nameof(myInstance.Property);    //"myInstance.Property"

    Exception Filters

    This is about the ability to filter exceptions in a catch block based on more than the exception class itself:

    try
    {
    //…
    }
    catch (MyException ex) if (ex.Code == 42)
    {
    //…
    }
    catch (MyOtherException ex) if (Check(ex))
    {
    //…
    }

    Notice that you can use methods in the filter clause, not just simple comparisons.

    String Interpolation

    This is one of my favorites: adding field, variable and method calls in the middle of a string, and having it interpreted at runtime:

    var variable = $"This is i: {i}";
    var property = $"A property: {this.Property}";
    var method = $"Filename: {Path.GetFullPath(filename)}";
    var format = $"Short date: {DateTime.Now:d}";

    Very similar to String.Format, but easier to use.

    Null-Conditional Operator

    Another personal favorite! No need for repeated null checks in deep property accesses or event handlers, the compiler takes care of it for us:

    var p = myInstance?.myProperty?.myNestedProperty;
     
    publicevent EventHandler MyEvent;
     
    publicvoid OnMyEvent(EventArgs e)
    {
    this.MyEvent?.Invoke(this, e);
    }

    If either myInstance or myProperty are null, null will be returned. It even works for events, as you can see.

    Using Static Members

    Besides bringing namespace types into context, using can now be used to do the same with static methods! For instance, take Console.WriteLine:

    using WriteLine = System.Console.WriteLine;
    //static method WriteLine only
    WriteLine("Hello, World");
     
     
    using System.Linq.Enumerable;
    //all extension methods of Enumerable
    var numbers = new [] { 1, 2, 3 };
    var even = numbers.Where(x => (x % 2) == 0);

    This will come in handy, to avoid type clashes. We just import the methods we’re interested in.

    Index Member Syntax

    A new notation for creating dictionary instances is introduced:

    var dict = new Dictionary<int, string>
    {
        [1] = "one",
        [2] = "two"
    };

    Async in Catch and Finally Blocks

    Using async in a catch or finally block is now valid:

    try
    {
    //...
    }
    catch (Exception exception)
    {
        await LogAsync(exception);
    }
    finally
    {
        await ReleaseAsync();
    }

    Extension Add Methods in Collection Initializers

    Starting with C# 4 (.NET 4), we could use an explicit enumeration syntax for creating collections (actually, any kind of classes that provided an Add method with a compatible parameters). Now extension methods are supported as well:

    publicstaticvoid Add(this ICollection<string> col, int i)
    {
        col.Add(i.ToString());
    }
     
    var col = new List<string>{ 1, 2, 3 };

    Here we are creating a List of strings, but we have an extension method that knows how to add integers to collections of strings.

    Declaration Expressions

    C# now allows us to declare variables immediately before they are to be used, like in using, while or for blocks:

    var success = int.TryParse("100", out var i);
     
    if ((var firstName = user.FirstName) != null) { }
     
    foreach (var n in var odd = numbers.Where(n => n % 2 == 1)) { }

    Conclusion

    All weighed up, there are some nice additions, others I don’t really see the point, but eventually I may.

    You can read everything about it in the Roslyn site at GitHub: https://github.com/dotnet/roslyn.







    Automating Microsoft Azure with PowerShell Review

    $
    0
    0

    Introduction

    I was again asked by Packt Publishing to review one of their books, this time, it was Automating Microsoft Azure with PowerShell. It came in good time, because I am starting to use Azure more and more, and PowerShell is a timesaver – actually, it is the only way to do lots of things. I have reviewed other books on Azure, which you can find at my blog, here.

    The book starts with an introductory chapter, where PowerShell and Azure are introduced, and then goes to the real thing. Not all APIs are covered, namely, Machine Learning, DocumentDB, BizTalk, Stream Analytics, etc, etc, which is not really surprising, since it seems that every month a new service pops out. The book is ~150 pages long, distributed between 10 chapters, which is perfectly acceptable for the amount of topics it covers. The target audience is clearly administrators with little knowledge of Azure.

    The author is John Chapman, which can be followed at Twitter as @chapmanjw.

    Chapter 1: Getting Started with Azure and PowerShell

    This chapter offers an introduction to PowerShell and how to install the Azure integration, retrieve subscription files and connecting to Azure. At the end of it we see how to create a blank website using PowerShell.

    Chapter 2: Managing Azure Storage with PowerShell

    This one is about storage. It explains about the major storage options that Azure has to offer – Table storage, Blobs, Queues and Files. Basic operations are discussed and we are presented with an example of a backup system.

    Chapter 3: Managing Azure Virtual Machines with PowerShell

    Next we have a discussion of the APIs available for the management of virtual machines (VMs). We learn how to create the many kinds of VMs existing in the Azure gallery, and performing all the typical operations, including creating snapshots and managing its storage.

    Chapter 4: Managing Azure SQL Databases with PowerShell

    In this chapter we learn how to create SQL servers and databases, configuring access to them, executing queries and finally exporting and importing data to and from.

    Chapter 5: Deploying and Managing Azure Websites

    Chapter 5 is about Azure Websites, the old name for Azure Web Apps. We learn how to create websites and how to provision them. Here I got the feeling that a lot is missing.

    Chapter 6: Managing Azure Virtual Networks with PowerShell

    A short chapter on how to configure virtual networks. Again, a lot more could be said on this.

    Chapter 7: Managing Azure Traffic Manager with PowerShell

    Azure Traffic Manager is Azure’s load-balancing mechanism. It explains how to configure websites for using the different load balancing techniques and load balancing profiles.

    Chapter 8: Managing Azure Cloud Services with PowerShell

    Cloud Services is another way to host VMs. The chapter explains how to create and manage cloud services, roles and endpoints and how retrieve Remote Desktop connection files.

    Chapter 9: Managing Azure Active Directory with PowerShell

    This chapter explains the basics of the Azure Active Directory (AD), the main authoritative source of identities in an Azure virtual network. We learn how to create and configure the basic options of an AD, managing users, groups and password policies. The example at the end of the chapter is about bulk creating users in the AD.

    Chapter 10: Automating Azure with PowerShell

    The final chapter talks about one of the automation mechanisms in Azure. We learn how to create an automation account and how to add runbooks to it.

    Conclusion

    The book is very succinct, and some topics would require substantially more coverage. It does provide some information enough to cover the basic usage of the covered Azure services.


    Case Study: Comparing ASP.NET Web Forms and MVC Implementations

    $
    0
    0

    Introduction

    Apparently, I am the last ASP.NET Web Forms developer in the whole World, which makes me kind of sad… anyway, after much crying, I decided to try out something: a comparison of Web Forms and MVC to solve a real life problem! Now, I only needed a problem to solve… Then, a colleague of mine came questioning me about captchas, so I thought, why not use it as my example? And here we are!

    Everyone is familiar with captchas. They are a way to prevent the automated use of web forms, so as to make sure that it is indeed an human that is providing the information. There are lots of implementations out there, and I don’t claim that mine is better or worse, I just implemented it in a couple of hours as an exercise.

    Core Library

    I designed a couple of classes, framework-agnostic, to hold my abstractions and sample implementations. These are:

    Common

    A succinct description is in order.

    CaptchaSecretPersister

    The contract for storing a secret key. Defines two methods, Store and Retrieve.

    SessionCaptchaSecretPersister

    An implementation of CaptchaSecretPersister that stores the secret key in the ASP.NET session.

    CaptchaImageTransformer

    The contract for transforming an image. Only has a single method, Transform.

    NullCaptchaImageTransformer

    Inherits from CaptchaImageTransformer, but doesn’t do anything.

    CaptchaSecretGenerator

    The contract for generating a new secret key (GetSecret).

    RandomCaptchaSecretGenerator

    An implementation of CaptchaSecretGenerator that generates a series of random letters.

    CaptchaImageProducer

    Base class for producing an image with a given secret key, dimensions, colors and an optional image transformer. Only has a single method, GetImage.

    GdiCaptchaImageProducer

    An implementation of CaptchaImageProducer that uses GDI+.

    CaptchaSecretValidator

    Base contract for secret key validation. Only defines a method, Validate.

    CaseInsensitiveCaptchaSecretValidator

    A case-insensitive string comparison implementation of CaptchaSecretValidator.

    And here is their code:

    publicabstractclass CaptchaSecretPersister
    {
    publicabstractvoid Store(String secret);
     
    publicabstract String Retrieve();
    }
     
    publicsealedclass SessionCaptchaSecretPersister : CaptchaSecretPersister
    {
    publicstaticreadonly CaptchaSecretPersister Instance = new SessionCaptchaSecretPersister();
     
    internalconst String Key = "Captcha";
     
    publicoverridevoid Store(String secret)
        {
            HttpContext.Current.Session[Key] = secret;
        }
     
    publicoverride String Retrieve()
        {
    return HttpContext.Current.Session[Key] as String;
        }
    }
     
    publicabstractclass CaptchaImageTransformer
    {
    publicabstractvoid Transform(Graphics g);
    }
     
    publicsealedclass NullCaptchaImageTransformer : CaptchaImageTransformer
    {
    publicstaticreadonly CaptchaImageTransformer Instance = new NullCaptchaImageTransformer();
     
    publicoverridevoid Transform(Graphics g)
        {
    //do nothing
        }
    }
     
    publicabstractclass CaptchaSecretGenerator
    {
    publicabstract String GetSecret(UInt32 length);
    }
     
    publicsealedclass RandomCaptchaSecretGenerator : CaptchaSecretGenerator
    {
    publicstaticreadonly CaptchaSecretGenerator Instance = new RandomCaptchaSecretGenerator();
     
    publicoverride String GetSecret(UInt32 length)
        {
            var builder = new StringBuilder();
            var rand = new Random();
     
    for (var i = 0; i < length; i++)
            {
                var ch = (Char)('A' + rand.Next(26));
                builder.Append(ch);
            }
     
    return builder.ToString();
        }
    }
     
    publicabstractclass CaptchaImageProducer
    {
    publicabstract Image GetImage(Int32 width, Int32 height, String secret, Color foreColor, Color backColor, CaptchaImageTransformer transformer);
    }
     
    publicsealedclass GdiCaptchaImageProducer : CaptchaImageProducer
    {
    publicstaticreadonly CaptchaImageProducer Instance = new GdiCaptchaImageProducer();
     
    publicoverride Image GetImage(Int32 width, Int32 height, String secret, Color foreColor, Color backColor, CaptchaImageTransformer transformer)
        {
            var img = new Bitmap(width, height, PixelFormat.Format32bppArgb);
     
    using (var graphics = Graphics.FromImage(img))
    using (var font = new Font(FontFamily.GenericSansSerif, 10F))
    using (var color = new SolidBrush(foreColor))
            {
                graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
                graphics.Clear(backColor);
                graphics.DrawString(secret, font, color, 0F, 0F);
     
    if (transformer != null)
                {
                    transformer.Transform(graphics);
                }
     
    return img;
            }
        }
    }
     
    publicabstractclass CaptchaSecretValidator
    {
    publicabstract Boolean Validate(String storedSecret, String secret);
    }
     
    publicsealedclass CaseInsensitiveCaptchaSecretValidator : CaptchaSecretValidator
    {
    publicstaticreadonly CaptchaSecretValidator Instance = new CaseInsensitiveCaptchaSecretValidator();
     
    publicoverride Boolean Validate(String storedSecret, String secret)
        {
    return String.Equals(storedSecret, secret, StringComparison.OrdinalIgnoreCase);
        }
    }

    Noteworthy:

    • Base classes are always abstract;
    • Actual implementations are sealed, stateless, and therefore define a static read only field, to avoid multiple instantiations.

    Both implementations, Web Forms and MVC, will use these classes.

    Web Forms

    So let’s start playing. Web Forms has the concept of validators. A validator must implement interface IValidator, and a BaseValidator class exists to make the task easier. When a form is submitted by a control that triggers validation, such as Button, all registered validators (Page.Validators) of the same validation group (ValidationGroup) as the trigger control are fired (Validate is called). The page will be considered valid if all validators have their IsValid property set to true. Knowing this, I created a custom control to display the captcha image and perform its validation:

    publicsealedclass CaptchaImage : WebControl, IValidator
    {
    public CaptchaImage() : base(HtmlTextWriterTag.Img)
        {
    this.CaptchaSecretGenerator = RandomCaptchaSecretGenerator.Instance;
    this.CaptchaImageTransformer = NullCaptchaImageTransformer.Instance;
    this.CaptchaImageProducer = GdiCaptchaImageProducer.Instance;
    this.CaptchaSecretPersister = SessionCaptchaSecretPersister.Instance;
    this.CaptchaSecretValidator = CaseInsensitiveCaptchaSecretValidator.Instance;
     
    this.CaptchaLength = 4;
    this.CaptchaFormat = ImageFormat.Png;
     
    this.ForeColor = Color.Black;
    this.BackColor = Color.Transparent;
    this.AlternateText = String.Empty;
    this.ControlToSetError = String.Empty;
    this.ControlToValidate = String.Empty;
     
            (thisas IValidator).IsValid = true;
        }
     
    public CaptchaSecretPersister CaptchaSecretPersister { get; set; }
     
    public CaptchaSecretGenerator CaptchaSecretGenerator { get; set; }
     
    public CaptchaImageTransformer CaptchaImageTransformer { get; set; }
     
    public CaptchaImageProducer CaptchaImageProducer { get; set; }
     
    public CaptchaSecretValidator CaptchaSecretValidator { get; set; }
     
        [DefaultValue("")]
    public String AlternateText { get; set; }
     
        [DefaultValue(4)]
    public UInt32 CaptchaLength { get; set; }
     
        [DefaultValue(typeof(ImageFormat), "Png")]
    public ImageFormat CaptchaFormat { get; set; }
     
        [DefaultValue("")]
        [IDReferenceProperty]
        [TypeConverter(typeof(ControlIDConverter))]
    public String ControlToValidate { get; set; }
     
        [DefaultValue("")]
        [IDReferenceProperty]
        [TypeConverter(typeof(ControlIDConverter))]
    public String ControlToSetError { get; set; }
     
        [DefaultValue("")]
    public String ErrorMessage { get; set; }
     
     
    publicevent EventHandler ValidationSuccess;
    publicevent EventHandler ValidationFailure;
    publicevent EventHandler ValidationComplete;
     
    privatevoid OnValidationSuccess()
        {
            var handler = this.ValidationSuccess;
     
    if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
     
    privatevoid OnValidationComplete()
        {
            var handler = this.ValidationComplete;
     
    if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
     
    privatevoid OnValidationFailure()
        {
            var handler = this.ValidationFailure;
     
    if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    private ITextControl FindTextControl(String id)
        {
    returnthis.NamingContainer.FindControl(id) as ITextControl;
        }
     
    protectedoverridevoid OnInit(EventArgs e)
        {
    if (this.Enabled == true)
            {
    this.Page.Validators.Add(this);
            }
     
    base.OnInit(e);
        }
     
    protectedoverridevoid Render(HtmlTextWriter writer)
        {
            var secret = this.CaptchaSecretGenerator.GetSecret(this.CaptchaLength);
     
    this.CaptchaPersister.Store(secret);
     
    using (var img = this.CaptchaImageProducer.GetImage((Int32)this.Width.Value, (Int32)this.Height.Value, secret, this.ForeColor, this.BackColor, this.CaptchaImageTransformer))
    using (var stream = new MemoryStream())
            {
                img.Save(stream, this.CaptchaFormat);
     
    this.Attributes[HtmlTextWriterAttribute.Src.ToString().ToLower()] = String.Format("data:image/{0};base64,{1}", this.CaptchaFormat.ToString().ToLower(), Convert.ToBase64String(stream.ToArray()));
    this.Attributes[HtmlTextWriterAttribute.Alt.ToString().ToLower()] = this.AlternateText;
            }
     
    base.Render(writer);
     
            var val = thisas IValidator;
     
    if (val.IsValid == false)
            {
                var errorControl = this.FindTextControl(this.ControlToSetError);
     
    if (errorControl != null)
                {
                    errorControl.Text = this.ErrorMessage;
                }
    else
                {
                    writer.Write(this.ErrorMessage);
                }
            }
        }
     
        Boolean IValidator.IsValid { get; set; }
     
    void IValidator.Validate()
        {
            var val = thisas IValidator;
            val.IsValid = true;
     
            var secretControl = this.FindTextControl(this.ControlToValidate);
    if (secretControl != null)
            {
                var storedSecret = this.CaptchaSecretPersister.Retrieve();
     
                val.IsValid = this.CaptchaSecretValidator.Validate(storedSecret, secretControl.Text);
     
    if (val.IsValid == true)
                {
    this.OnValidationSuccess();
                }
    else
                {
    this.OnValidationFailure();
                }
     
    this.OnValidationComplete();
            }
        }
    }

    The CaptchaImage class inherits from WebControl, so that we can leverage some of its properties (ForeColor, BackColor), and defines a containing tag of IMG.

    In its constructor, all relevant properties are instantiated to sensible defaults, these include a number of properties for the core library classes (CaptchaSecretPersister, CaptchaSecretGenerator, CaptchaImageProducer, CaptchaImageTransformer and CaptchaSecretValidator). Other important properties are:

    • ErrorMessage: the message to display in case of a validation error;
    • AlternateText: the image’s ALT text;
    • CaptchaLength: the desired length of the secret key; the default is 4;
    • CaptchaFormat: the image format of choice, where the default is ImageFormat.Png;
    • ControlToValidate: the required ID of a server-side control containing text (must implement ITextControl);
    • ControlToSetError: an optional ID for a control that can take text (must implement ITextControl too), which will be used to set the ErrorMessage value.

    The IsValid property, from IValidator, is implemented privately because most of the time we do not want to mess with it. Another inherited property, Enabled, can be used to turn off validation.

    Then we have three events:

    • ValidationSuccess: raised when the validation occurs and is successful;
    • ValidationFailure: raised when a failed validation occurs;
    • ValidationComplete: always raised when a validation is performed, regardless of its outcome.

    When the control loads, OnInit is called, and it registers itself with the Validators collection, this is a required step. In Render, it generates a secret key, stores it, produces an image from it and renders it as an inline image using the Data URI format. It is the same approach that I talked about a numberoftimes before. When the control receives a validation request, the Validate method is called, and the provided key is validated against the stored one.

    A typical usage would be like this:

    <web:CaptchaImage runat="server" ID="captcha" Width="50px" Height="25px" BackColor="Blue" AlternateText="Captcha riddle" ControlToValidate="text" ErrorMessage="Invalid captcha" OnValidationSuccess="OnSuccess" OnValidationFailure="OnFailure" OnValidationComplete="OnComplete" />

    Whereas the registered event handlers might be:

    protectedvoid OnSuccess(Object sender, EventArgs e)
    {
    this.captcha.Visible = false;
    }
     
    protectedvoid OnFailure(Object sender, EventArgs e)
    {
    }
     
    protectedvoid OnComplete(Object sender, EventArgs e)
    {
    }

    Easy, don’t you think? Now, let’s move on to MVC!

    MVC

    In MVC we don’t really have controls, because of the separation of concerns and all that. The closest we have at the moment are extension methods, let’s have a look at the Captcha method:

    publicstatic IHtmlString Captcha(this HtmlHelper html, Int32 width, Int32 height, UInt32 length = 4, String alternateText = "", ImageFormat captchaFormat = null, Color? foreColor = null, Color? backColor = null)
    {
        var captchaSecretGenerator = DependencyResolver.Current.GetService<CaptchaSecretGenerator>();
        var captchaSecretPersister = DependencyResolver.Current.GetService<CaptchaSecretPersister>();
        var captchaImageProducer = DependencyResolver.Current.GetService<CaptchaImageProducer>();
        var captchaImageTransformer = DependencyResolver.Current.GetService<CaptchaImageTransformer>();
     
        var secret = captchaSecretGenerator.GetSecret(length);
     
        captchaSecretPersister.Store(secret);
     
    using (var img = captchaImageProducer.GetImage(width, height, secret, foreColor ?? Color.Black, backColor ?? Color.Transparent, captchaImageTransformer))
    using (var stream = new MemoryStream())
        {
            img.Save(stream, captchaFormat ?? ImageFormat.Png);
     
            var tag = String.Format("<img src=\"data:image/{0};base64,{1}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\"/>", (captchaFormat ?? ImageFormat.Png).ToString().ToLower(), Convert.ToBase64String(stream.ToArray()), width, height, alternateText);
     
    returnnew HtmlString(tag);
        }
    }

    It is unpractical to pass all components, so we are relying on MVC’s built-in dependency injection framework. I used Microsoft Unity as my Inversion of Control (IoC) container, and to make it integrate with MVC, I installed the Unity.MvcNuGet package:

    image

    Then I had to register the actual implementations for my services, this is usually done in the App_Start\UnityConfig.cs file’s RegisterTypes method:

    container.RegisterInstance<CaptchaSecretGenerator>(RandomCaptchaSecretGenerator.Instance);
    container.RegisterInstance<CaptchaImageProducer>(GdiCaptchaImageProducer.Instance);
    container.RegisterInstance<CaptchaSecretPersister>(SessionCaptchaSecretPersister.Instance);
    container.RegisterInstance<CaptchaImageTransformer>(NullCaptchaImageTransformer.Instance);
    container.RegisterInstance<CaptchaSecretValidator>(CaseInsensitiveCaptchaSecretValidator.Instance);

    The code from Unity.Mvc automatically hooks Unity with the DependencyResolver class, so we don’t have to do it ourselves. For an example implementation, I once wrote a post on it that you can check out, if you are curious.

    Now, we need two things: a view and a controller. Let’s look at the view first (simplified):

    @Html.Captcha(50, 25)
    @using (Html.BeginForm("Validate", "Home"))
    {
        @Html.TextBox("secret")
    <button>Validate</button>
    }

    As you can see, the form will post to the Validate method of an HomeController. The output of the Captcha method doesn’t have to be inside the form, because it merely renders an IMG tag.

    As for the controller, the Validate method is pretty straightforward:

    public ActionResult Validate(String secret)
    {
        var captchaPersister = DependencyResolver.Current.GetService<CaptchaSecretPersister>();
        var captchaSecretValidator = DependencyResolver.Current.GetService<CaptchaSecretValidator>();
     
        var storedSecret = captchaPersister.Retrieve();
        var isValid = captchaSecretValidator.Validate(storedSecret, secret);
     
        if (isValid == true)
        {
            return this.View("Success");
        }
        else
        {
            return this.View("Failure");
        }
    }

    It tries to obtain the services from the DependencyResolver, validates the supplied secret key and then returns the proper view, accordingly.

    Conclusion

    So, which implementation do you prefer? The Web Forms one, unsurprisingly, only needs a single class, CaptchaImage, and, of course, a host page; the assembly containing it can be referenced by other projects and used very easily. As for the MVC version, we need to have the Captcha extension method, the IoC bootstrapping/registration code, a view and a controller with a Validate method similar to the one presented. The extension method and the controller may come from another referenced assembly, it needs some work, but can definitely be done.

    Of course, this is a sample implementation, things can be done in a myriad of alternative ways. I’d like to hear from you about the problems with this particular implementation, and alternative ways to do it. By the way, feel free to use and modify the code anyway you want to, I will soon make it available in my GitHub account.

    SharePoint Pitfalls: Publishing Pages in Document Libraries Other Than Pages

    $
    0
    0

    This one is a classic: the SharePoint Publishing feature in a Publishing Site creates a document library by the name of Pages; this is where you can store your publishing pages.

    A common request is to have more of these document libraries, that is because we cannot create publishing pages anywhere else. The problem is, it is unsupported, God knows why!

    What you can do is rename the document library to something else. SharePoint will look for the library id in the site’s property bag, under __PagesListId, so only need to update this value accordingly:

    web.AllProperties["__PagesListId"] = newDocLibId.ToString();
    web.Update();

    Now, there are some solutions over the Internet that claim to go around this limitation, but none of them is supported, so proceed with care!

    SharePoint Pitfalls Index

    SharePoint Pitfalls: Master Pages in Page Layouts

    $
    0
    0

    When you deploy a page layout, you may want to add your own master page as well. I find it useful to add my own custom master pages and reference them directly, in the same or a dependent feature. You might be surprised, however, that it doesn’t work exactly how you’d expect!

    The issue is, page layouts will ignore silently anything in the MasterPageFile attribute if it isn’t one of the standard tokens for the system or custom master pages. ~masterurl/default.master and ~masterurl/custom.master. The solution is to have a code behind class and specify the master page in the OnPreInit method (anywhere else won’t work):

    protectedoverridevoid OnPreInit(EventArgs e)
    {
    base.OnPreInit(e);
     
    this.MasterPageFile = "~site/_catalogs/masterpage/CustomMasterPage.master":
    }

    SharePoint Pitfalls: GUID Formats

    $
    0
    0

    SharePoint uses GUIDs extensively. The problem is, it accepts them in different formats, in different locations:

    • The ListId and ListName properties of the DataFormWebPart, feature, site column definitions, solution manifests, all expect a GUID in the {A1ADD3D1-B21F-4F93-9B86-B1FE332424D0} format (inside { });
    • In an Elements.xml file or in a Parameter inside a data source, use B8381C7D-3B8D-46D8-8E40-C96E1FF4C308;
    • In the URL, you need to replace - for %2D, { for %7B and } for %7D, as in %7BA1ADD3D1%2DB21F%2D4F93%2D9B86%2DB1FE332424D0%7D;
    • In feature receivers tokens and in New-SPTrustedSecurityTokenIssuer and the likes, GUIDs have to be in lowercase ($SharePoint.Type.edd0669b-2393-4fe6-988d-17a2De06c6e4.FullName$).
    Viewing all 404 articles
    Browse latest View live


    <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>