X Blogs

who you gonna call?

Automatic SQL Azure backup part 1

clock November 18, 2011 23:24 by author Rok Bermež
Backup for SQL Azure was one of the most voted-on features since the beginning. Sure, we had SQL Migration wizard, BCP, SSIS, PowerShell cmdlets from Cerebrata , and later a very nice tool from RedGate (that I still use a lot) - SQL Azure backup. All of them have one flaw, there are either impossible or very hard to use for automatic backups that require no on premises infrastructure.
For a while now, Import and Export CTP functionality has been available through Windows Azure management portal, that exports or imports Sql DacPac package. This is the exact functionality that should be integrated with my SQL Azure using cloud applications.
MSDN documentation for that REST API seems to be completely lacking, but fortunately there are some SQL DAC Examples on CodePlex project that can we can use to see how it’s done.
First, we add a service reference to http://dacdc.cloudapp.net/DACWebService.svc/mex and generate required proxy classes.

Now we can make WebRequests for specific actions (import,export, status) to URLs, that are specific to each Windows Azure datacenter. Here is the mapping:

RegionUrl
North Central US https://ch1prod-dacsvc.azure.com/DACWebService.svc
South Central US https://sn1prod-dacsvc.azure.com/DACWebService.svc
North Europe https://db3prod-dacsvc.azure.com/DACWebService.svc
West Europe https://am1prod-dacsvc.azure.com/DACWebService.svc
East Asia https://hkgprod-dacsvc.azure.com/DACWebService.svc
Southeast Asia https://sg1prod-dacsvc.azure.com/DACWebService.svc

 

Export

To create a backup to storage we need to create an object of type ExportInput and POST it to datacenters url + “/export”.

 

public Guid ExportToStorage(string storageContainer, string fileName, BlobContainerPublicAccessType blobContainerPublicAccessType = BlobContainerPublicAccessType.Off)
        {
            var blobCredentials = GetBlobCredentials(storageContainer, fileName, true, blobContainerPublicAccessType);
            var exportRequest = new ExportInput
            {
                BlobCredentials = blobCredentials,
                ConnectionInfo = _connectionInfo
            };
            var req = GetRequest(new Uri(_dataCenterUrl + "/Export"), RequestMethod.POST);
            var serializer = new DataContractSerializer(typeof(ExportInput));
            var requestStream = req.GetRequestStream();
            serializer.WriteObject(requestStream, exportRequest);
            requestStream.Close();
            var resp = req.GetResponse();
            return GetGuidFromResponse(resp);
        }
        private BlobStorageAccessKeyCredentials GetBlobCredentials(string storageContainer, string fileName, bool createIfNotExist = false, BlobContainerPublicAccessType blobContainerPublicAccessType = BlobContainerPublicAccessType.Off)
        {
            var storageCredentials = new StorageCredentialsAccountAndKey(_storageConnectionInfo.AccountName, _storageConnectionInfo.AccountKey);
            var storageAccount = new CloudStorageAccount(storageCredentials, _storageConnectionInfo.UseHttps);
            var cloudBlobClient = storageAccount.CreateCloudBlobClient();
            var cloudBlobContainer = cloudBlobClient.GetContainerReference(storageContainer);
            if (createIfNotExist)
            {
                if (cloudBlobContainer.CreateIfNotExist())
                {
                    var permissions = cloudBlobContainer.GetPermissions();
                    permissions.PublicAccess = blobContainerPublicAccessType;
                    cloudBlobContainer.SetPermissions(permissions);
                }
            }
            var cloudBlob = cloudBlobContainer.GetBlobReference(fileName);
            var backupBlobUri = cloudBlob.Uri.ToString();
            var blobCredentials = new BlobStorageAccessKeyCredentials
            {
                StorageAccessKey = _storageConnectionInfo.AccountKey,
                Uri = backupBlobUri,
            };
            return blobCredentials;
        }
        private HttpWebRequest GetRequest(Uri uri, RequestMethod requestMethod)
        {
            var req = (HttpWebRequest)WebRequest.Create(uri);
            req.Method = requestMethod.ToString().ToUpper();
            req.ContentType = "application/xml";
            return req;
        }

Import

For import the process is very similar, we have object of type ImportInput and POST it to datacenters url + “/import”.

 

 public Guid ImportFromStorage(string storageContainer, string fileName, SqlAzureEdition sqlAzureEdition = SqlAzureEdition.Web, SqlAzureSize sqlAzureSize=SqlAzureSize.GB_1, string newDbName=null)
        {
            var blobCredentials = GetBlobCredentials(storageContainer,fileName);
            ImportInput importRequest = new ImportInput();
            BlobCredentials creds = blobCredentials;
            importRequest.BlobCredentials = creds;
            importRequest.AzureEdition = sqlAzureEdition.ToString().ToLower();
            importRequest.DatabaseSizeInGB = (int)sqlAzureSize;
            importRequest.ConnectionInfo = (String.IsNullOrEmpty(newDbName)) ? _connectionInfo : new ConnectionInfo() { DatabaseName = newDbName, ServerName = _connectionInfo.ServerName, UserName = _connectionInfo.UserName, Password = _connectionInfo.Password};
            var req = GetRequest(new Uri(_dataCenterUrl + "/Import"), RequestMethod.POST);
            var serializer = new DataContractSerializer(typeof(ImportInput));
            var requestStream = req.GetRequestStream();
            serializer.WriteObject(requestStream, importRequest);
            requestStream.Close();
            var resp = req.GetResponse();
            return GetGuidFromResponse(resp);
        }

Status

Both actions return GUID representing current action that we can use to check if operation was successful. We do this by making GET request to datacenters url + “/status? servername={0}&username={1}&password={2} &reqId={3}”. If we want to get history and their statuses for this datacenter we can make the same request without reqId.

 

        public StatusInfo GetStatusInfo(Guid requestId)
        {
            string uriBuilder = _dataCenterUrl + string.Format("/Status?servername={0}&username={1}&password={2}&reqId={3}", _connectionInfo.ServerName, _connectionInfo.UserName, _connectionInfo.Password, requestId.ToString());
            var req = GetRequest(new Uri(uriBuilder), RequestMethod.GET);
            var response = req.GetResponse();
            var statusInfos = GetStatusInfoFromResponse(response);
            return statusInfos[0];
        }

 

Here ( SqlAzure.rar (22,71 kb) ) you can download a complete library that you can use in your Azure Worker tasks to automatically back up you SQL Azure databases. Next.... how to create cheduler that uses it.

 



Azure AppFabric Cache HowTo

clock May 3, 2011 04:24 by author Rok Bermež
Well since we now have Azure AppFabric Cache available, let’s get a head start on how to use it in your Cloud ASP.NET (MVC) application. First, you need to have AppFabric 1.0 April Refresh SDK installed on your machine so grab it at here.
Next, go to Windows Azure Management portal. Log in, go to AppFabric/Cache and create new service namespace: wait for the service to be activated.

Then click 'View Client Configuration Button'

you will get a nice pre prepared configuration settings (with all those pesky security information included) for your app:
now we have all the pieces of the puzzle ready, all we have to do is to add references to caching dlls (located at C:\Program Files\Windows Azure AppFabric SDK\V1.0\Assemblies\NET4.0\Cache) to our application and change web.config with the settings given by previous step.

You would always need to put cache section in <configSections> node:
<section name="dataCacheClients" 
             type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection,
Microsoft.ApplicationServer.Caching.Core"
allowLocation="true" allowDefinition="Everywhere"/>
and configure your Cache EndPoints:
<dataCacheClients>
    <dataCacheClient name="default">
      <hosts>
        <host name="ntkonferenca.cache.windows.net" cachePort="22233" />
      </hosts>
      <securityProperties mode="Message">
        <messageSecurity
authorizationInfo="1AmN0tT371NgUtH@T">
        </messageSecurity>
      </securityProperties>
    </dataCacheClient>
    <dataCacheClient name="SslEndpoint">
      <hosts>
        <host name="ntkonferenca.cache.windows.net" cachePort="22243" />
      </hosts>
      <securityProperties mode="Message" sslEnabled="true">
        <messageSecurity
authorizationInfo="1AmN0tT371NgUtH@T">
        </messageSecurity>
      </securityProperties>
    </dataCacheClient>
  </dataCacheClients>
If your application uses Session State and you want it to use Azure AppFabric Cache (which you do) you change your <sessionState> node to:
    <sessionState mode="Custom" customProvider="AppFabricCacheSessionStoreProvider">
      <providers>
        <add name="AppFabricCacheSessionStoreProvider"
             type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, 
Microsoft.Web.DistributedCache"
cacheName="default" useBlobMode="true" dataCacheClientName="default" /> </providers> </sessionState>
and the same for OutputCache by changing <caching> note:
<caching>
    <outputCacheSettings enableFragmentCache="true" defaultProvider="DistributedCache">
      <outputCacheProfiles>
        <add name="default" duration="43000" />
        <add name="DistributedCache"
                       type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, 
Microsoft.Web.DistributedCache"
cacheName="default" dataCacheClientName="default" /> </outputCacheProfiles> </outputCacheSettings> </caching>
That’s it, nothing needs to be changed in your code, your app is configured and ready to be published to the cloud. AppFabric Cache is not a free service even if you won’t be charged anything for its use prior to August 1, 2011. After that the prices are:
  • 128 MB cache for $45.00/month
  • 256 MB cache for $55.00/month
  • 512 MB cache for $75.00/month
  • 1 GB cache for $110.00/month
  • 2 GB cache for $180.00/month
  • 4 GB cache for $325.00/month
In my next post, Ill tackle with using AppFabric Cache without using prepared providers by simple GET and PUT statements (lets get rid of HttpRuntime.Cache as well).

 



Windows Azure Cache Dependency

clock April 11, 2011 08:07 by author Rok Bermež

We are supposed to get Windows AppFabric Cache real soon, but till than form time to time we need to synchronize content cached inside our Web roles. SqlDependency is one way, but it cannot solve all problems (especialy those that are not based on SQL data). So to help with the matter I wrote AzureStorageCacheDependency that uses Azure storage to know when data is outdated and cache shloul be cleared. If anyone is in need of something similar, here it goes:

public class AzureStorageCacheDependency : System.Web.Caching.CacheDependency
    {
        private System.Threading.Timer _timer;
        private int _poolTime;
        private CloudBlob _blob;
        private string _key;

        public AzureStorageCacheDependency(string connectionString, string conteinerAddress, string blobAddress, int poolTime = 5000)
        {
            _poolTime = poolTime;
            using (AzureContext azureContext = new AzureContext(true))
            {
                var storageAccount = CloudStorageAccount.Parse(connectionString);
                CloudBlobClient blobStorage = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer container = blobStorage.GetContainerReference(conteinerAddress.ToLower());
                container.CreateIfNotExist();
                _blob = container.GetBlockBlobReference(blobAddress.ToLower());
                if (!Exists(_blob))
                {
                    Reset();
                }
                else
                {
                    _key = _blob.DownloadText();
                }
            }
            _timer = new Timer(new System.Threading.TimerCallback(CheckDependencyCallback), this, 0, _poolTime);
        }



        public void Reset()
        {
            _key = Guid.NewGuid().ToString();
            _blob.UploadText(_key);
        }

        private void CheckDependencyCallback(object sender)
        {
                if (!Exists(_blob) || _key != _blob.DownloadText())
                {
                    NotifyDependencyChanged(this, EventArgs.Empty);
                    _timer.Dispose();
                }
        }

        public static bool Exists(CloudBlob blob)
        {
            try
            {
                blob.FetchAttributes();
                return true;
            }
            catch (StorageClientException e)
            {
                if (e.ErrorCode == StorageErrorCode.ResourceNotFound)
                {
                    return false;
                }
                else
                {
                    throw;
                }
            }
        }
    }

    public class AzureContext : IDisposable
    {
        HttpContext _oldHttpContext;
        bool _restoreOldHttpContext = false;


        public AzureContext(bool forceSettingContextToNull = false)
        {
            if (forceSettingContextToNull)
            {
                _oldHttpContext = HttpContext.Current;
                HttpContext.Current = null;
                _restoreOldHttpContext = true;
            }
            else
            {
                try
                {
                    HttpResponse response = HttpContext.Current.Response;
                }
                catch (HttpException)
                {
                    _oldHttpContext = HttpContext.Current;
                    HttpContext.Current = null;
                    _restoreOldHttpContext = true;
                }
            }
        }


        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_restoreOldHttpContext)
                {
                    HttpContext.Current = _oldHttpContext;
                }
            }
        }


        public void Dispose()
        {
            Dispose(true);
        }


        ~AzureContext()
        {
            Dispose(false);
        }
    }


ASP.NET MVC 3 AJAX REDIRECT RESULT

clock April 5, 2011 23:31 by author Rok Bermež
From time to time, we need to selectively redirect the browser to another location as a 
result of an AJAX action. Just returning RedirectResult won’t do the trick (even if we
are used to similar functionality in ASP.NET AJAX in combination with WebForms ). Here
is a very simple RedirectResult thet will be appropriate in those scenarios:

public class AjaxRedirectResult : RedirectResult { public AjaxRedirectResult(string url): base(url){} public override void ExecuteResult(ControllerContext context) { if (context.RequestContext.HttpContext.Request.IsAjaxRequest()) { JavaScriptResult result = new JavaScriptResult() { Script = String.Format("window.location='{0}';",
UrlHelper.GenerateContentUrl(Url, context.HttpContext)) }; result.ExecuteResult(context); } else base.ExecuteResult(context); } }


Windows Azure Full IIS

clock January 11, 2011 08:00 by author Rok Bermež

Some time ago I wrote how to deploy multitenant application to the Cloud. The process was tricky at best. With new Windows Azure SDK 1.3 things just got a lot simpler and I absolutely love it. The feature is called Full IIS and allows your web roles to access the full range of web server features that are available in on-premise IIS installations. However if you choose to use them, there are a few differences from the classic Azure Hosted Web Core (HWC) model.

First you need to tell Windows Azure SDK to use Full IIS instead of HWC and you do this by adding a valid <Sites> section to your ServiceDefinition.csdef  file.  By default Visual Studio will create HWC model definition like this:

    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
        </Bindings>
      </Site>
    </Sites>

You can easily customize it to define multiple web sites, or virtual apps (virtual directories are also supported now):

<Sites>
  <Site name="MainSite">
    <VirtualApplication name="WebApp1" physicalDirectory="D:\Delo\Projects\WebApp1\" />
    <Bindings>
      <Binding name="HttpIn" endpointName="HttpIn" />
    </Bindings>
  </Site>
  <Site name="AnotherSiteOrSubDomain" physicalDirectory="D:\Delo\Projects\ AnotherSiteOrSubDomain ">
    <Bindings>
      <Binding hostHeader="anothersiteorsubdomain.myall.si" name="HttpIn" endpointName="HttpIn"/>
    </Bindings>
  </Site>
</Sites>

Things are much more similar to on-premises application then in HWC model. While RoleEntryPoint  runs under different process (WaIISHost.exe) than your web roles  (w3wp.exe), OnStart method still gets called but configuration settings work a bit differently. You cannot register or store some static values to be available to all websites. Remember its running in a different process... so you wont be able to access its data. What I mean by this is, probably everyone dealing with Azure Development has something similar to this in their role onstart method:

CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>{
    configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});

While code is still perfectly sound, it wont do any good to our web roles, so the proper place to register it would by global.asax on ApplicationStart event. It all kind of makes sense, since different websites need different resources anyway.



MultipleGenericBindingGenerator for Ninject.Extensions.Conventions

clock January 11, 2011 02:55 by author Rok Bermež

Ninject.Extensions.Conventions provides convention based binding for Ninject modeled after the StructureMap 2.5 AssemblyScanner by Jeremy Miller.

When StructureMap users can use something like:

Scan(scanner =>
                {
                    scanner.AssembliesFromApplicationBaseDirectory(assembly => assembly.FullName.StartsWith("Ntk.Infrastructure."));
                    scanner.ConnectImplementationsToTypesClosing(typeof (IMessageHandler <,>));
                    scanner.ConnectImplementationsToTypesClosing(typeof (IMessageHandler <>));
                });

Ninject.Extensions.Conventions using GenericBindingGenerator can not:

            kernel.Scan(scanner =>
            {
                scanner.FromAssembliesMatching( "Ntk.Infrastructure.*.dll" );  
                scanner.BindWith(new GenericBindingGenerator(typeof(IMessageHandler<>)));
                scanner.BindWith(new GenericBindingGenerator(typeof(IMessageHandler<,>)));
                scanner.InTransientScope();
            });

So slightly modified version of GenericBindingGenerator called MultipleGenericBindingGenerator comes to the rescue:

            kernel.Scan(scanner =>
            {
                scanner.FromAssembliesMatching("Ntk.Infrastructure.*.dll");
                scanner.BindWith(new MultipleGenericBindingGenerator(typeof(IMessageHandler<>),typeof(IMessageHandler<,>)));
                scanner.InTransientScope();
            });

If anyone needs anything like this, here is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Ninject;
using Ninject.Activation;
using Ninject.Extensions.Conventions;

namespace TestProj{
    public class MultipleGenericBindingGenerator  : IBindingGenerator
    {
        private static readonly Type TypeOfObject = typeof (object);
        private readonly Type[] _contractTypes;

        /// <summary>
        /// Initializes a new instance of the <see cref="MultipleGenericBindingGenerator"/> class.
        /// </summary>
        /// <param name="contractTypes">Types of the contract.</param>
        public MultipleGenericBindingGenerator(params Type[] contractTypes)
        {
            foreach (var type in contractTypes)
            {
                if (!(type.IsGenericType || type.ContainsGenericParameters))
                {
                    throw new ArgumentException(String.Format("The contract must be an open generic type ({0}).",type.Name), "contractTypes");
                } 
            }
            _contractTypes = contractTypes;
        }

        #region Implementation of IBindingGenerator

        /// <summary>
        /// Processes the specified type creating kernel bindings.
        /// </summary>
        /// <param name="type">The type to process.</param>
        /// <param name="scopeCallback">the scope callback.</param>
        /// <param name="kernel">The kernel to configure.</param>
        public void Process( Type type, Func<IContext, object> scopeCallback, IKernel kernel )
        {
            Type interfaceType = ResolveClosingInterface( type );
            if ( interfaceType != null )
            {
                kernel.Bind( interfaceType ).To( type ).InScope( scopeCallback );
            }
        }

        #endregion

        /// <summary>
        /// Resolves the closing interface.
        /// </summary>
        /// <param name="targetType">Type of the target.</param>
        /// <returns></returns>
        public Type ResolveClosingInterface( Type targetType )
        {
            if ( targetType.IsInterface || targetType.IsAbstract )
            {
                return null;
            }

            do
            {
                Type[] interfaces = targetType.GetInterfaces();
                foreach ( Type @interface in interfaces )
                {
                    if ( !@interface.IsGenericType )
                    {
                        continue;
                    }

                    if (_contractTypes.Contains(@interface.GetGenericTypeDefinition()))
                    {
                        return @interface;
                    }
                }
                targetType = targetType.BaseType;
            } while ( targetType != TypeOfObject );

            return null;
        }
    }
}



T4MVC templates for strongly typed ASP.MVC

clock January 10, 2011 21:19 by author Rok Bermež

T4 templates for strongly typed ASP.MVC

 

MVC is a software pattern, that has been first introduced 1979 by Norwegian scientist Trygve Reenskaug.  The idea was to decouple the tight knot between views and models, to have a much more control over the software.

For example, very known ASP.NET 2.0 technology had the implementation of views, but controllers and models were combined in the code behind, which has the impact on the testing and other features, which is needed to build a easy proficient sustainable web solution.

Year ago Microsoft has launched a framework ASP.NET MVC for supporting software pattern and add additional value with different view engines , such as Razor, to eliminate this requirement. Since then, developers are having  few consideration about choosing between ASP.NET WebForms and ASP.NET MVC, but that is topic for another blog post.

MVC grew very quickly and alot of developers are using the new .NET framework to write efficient, light weight, powerfull web apps. Even though we do have a great enviroment for writing, testing, debugging  .NET apps, there is still a lack of string and mis-machted typos.

Consider following example:

<%:Html.ActionLink(»My link«,«Indeks«,«Home«) %>

This is a link to the Home controller, with a method Indeks. But wait, there is no indeks method there. It is a typo. Since we forgot to write x, instead of ks, we got a runtime error. We have to run the site, click of the link, read the error message, ask ourself, what did we do, use the debugger, run the site, check again, go through bunch of step, just because we made a typo.

This is the reason, why expert developers, such as david Ebbo, created a helper (T4 templates), that goes through the code and created a strongly typed strings for controllers, views, even a content.

Fixed upper example:

<%:Html.ActionLink(»My link«, MVC.Home.Index)%>

Its so easy. No more runtime checking, no repro bugs, even intellisense helps us understand, which name and even parameters we will use. 

You can use the following strongly typed helpers in the whole app, not only the views ( also in controllers, etc.)

It is quite simple to use it:

1.       Download the zip file on the codeplex site

2.       Required watching the David Ebbo intro with examples

3.       Unzip the file

4.       Add the 2 files in the root of your MVC app (T4MVC.tt and T4MVC.setting.t4)

5.       Build it

6.       Use it J

You can change the setting for t4 in the settings file to bend it to you will J

Happy no-typo coding.



RadEditor MVC Helper Sample

clock September 9, 2010 00:09 by author Rok Bermež

I was asked for RadEditor MVC helper, so here it goes (copy paste code out) :

        public static MvcHtmlString RadEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
        {

            return RadEditorFor(htmlHelper, expression, ((IDictionary<string, object>)null));
        }

        public static MvcHtmlString RadEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) where TModel : class
        {
            return RadEditorFor(htmlHelper, expression, new RouteValueDictionary(htmlAttributes));
        }

        public static MvcHtmlString RadEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) where TModel : class
        {
            string name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText((LambdaExpression)expression));
            TProperty value = ExpressionHelper2.GetValue(htmlHelper, expression);
            return RadEditor(htmlHelper, name, value, htmlAttributes);
        }

        public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name)
        {
            return RadEditor(htmlHelper, name, null);
        }

        public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name, object value)
        {
            return RadEditor(htmlHelper, name, null, ((IDictionary<string, object>)null));
        }

        public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes)
        {
            return RadEditor(htmlHelper, name, value, new RouteValueDictionary(htmlAttributes));
        }

        public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> htmlAttributes)
        {
            if (String.IsNullOrEmpty(name))
            {
                name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
                if (string.IsNullOrEmpty(name))
                {
                    throw new ArgumentException("name");
                }
            }
            if (htmlAttributes == null) htmlAttributes = new Dictionary<string, object>();
            Page page = new Page();
            RadMvcScriptManager mvcScriptManager = new RadMvcScriptManager();
            mvcScriptManager.EnableViewState = false;
            page.Controls.Add(mvcScriptManager);
            RadStyleSheetManager radStyleSheetManager = new RadStyleSheetManager();
            page.Controls.Add(radStyleSheetManager);

            //string id = name.Replace(".", "_");
            RadEditor radEditor = new RadEditor();

            radEditor.ID = name + "_radeditor";
            radEditor.ClientIDMode = ClientIDMode.Static;

            radEditor.ImageManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName;
            radEditor.ImageManager.MaxUploadFileSize = 3000000;
            radEditor.ImageManager.ViewPaths = new string[] { "uploaded/images" };
            radEditor.ImageManager.UploadPaths = new string[] { "uploaded/images" };
            radEditor.ImageManager.DeletePaths = new string[] { "uploaded/images" };

            radEditor.DocumentManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName;
            radEditor.DocumentManager.MaxUploadFileSize = 20000000;
            radEditor.DocumentManager.ViewPaths = new string[] { "uploaded/documents" };
            radEditor.DocumentManager.UploadPaths = new string[] { "uploaded/documents" };
            radEditor.DocumentManager.DeletePaths = new string[] { "uploaded/documents" };

            radEditor.MediaManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName;
            radEditor.MediaManager.MaxUploadFileSize = 50000000;
            radEditor.MediaManager.ViewPaths = new string[] { "uploaded/media" };
            radEditor.MediaManager.UploadPaths = new string[] { "uploaded/media" };
            radEditor.MediaManager.DeletePaths = new string[] { "uploaded/media" };

            radEditor.FlashManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName;
            radEditor.FlashManager.MaxUploadFileSize = 50000000;
            radEditor.FlashManager.ViewPaths = new string[] { "uploaded/flash" };
            radEditor.FlashManager.UploadPaths = new string[] { "uploaded/flash" };
            radEditor.FlashManager.DeletePaths = new string[] { "uploaded/flash" };

            //radEditor.TemplateManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName;
            radEditor.TemplateManager.MaxUploadFileSize = 500000;
            radEditor.TemplateManager.ViewPaths = new string[] { "~/content/templates" };

            radEditor.NewLineBr = false;

            radEditor.Skin = "Vista";

            //radEditor.ToolsFile = "~/Content/administracija/EditorToolbar.xml";
            if (htmlAttributes.ContainsKey("ToolsFile")) radEditor.ToolsFile = htmlAttributes["ToolsFile"] as string;
            UIHintControlParameterDataAnnotationsModelMetadata mmd = (UIHintControlParameterDataAnnotationsModelMetadata)htmlHelper.ViewData.ModelMetadata;
            if (mmd.TemplateControlParameterExist("ToolBar"))
            {
                radEditor.ToolsFile = mmd.GetTemplateControlParameter<string>("ToolBar");
            }
            if (mmd.TemplateControlParameterExist("DisableHtmlFormating") && mmd.GetTemplateControlParameter<bool>("DisableHtmlFormating"))
            {
                radEditor.StripFormattingOptions = EditorStripFormattingOptions.None;
                radEditor.DisableFilter(Telerik.Web.UI.EditorFilters.ConvertToXhtml);

            }
            if (value != null) radEditor.Content = value as string;
            radEditor.DialogHandlerUrl = "/Telerik.Web.UI.DialogHandler.axd";
            page.Controls.Add(radEditor);
            StringWriter output = new StringWriter();
            HttpContext.Current.Server.Execute(page, output, false);

            return MvcHtmlString.Create(htmlHelper.Hidden("", "ToBeReplaced").ToString() + output.ToString());
        }


Telerik ASP.NET AJAX Controls in MVC project Part ||

clock September 4, 2010 00:09 by author Rok Bermež

Some controls explicitly require to be placed within

tag. To go around this issue you can do something like this (telerik reporting used in MVC project):
public class NoServerFormPage: Page
        {
            public override void VerifyRenderingInServerForm(Control control)
            {
                // to avoid the server form (<form runat="server">) requirement
            }
        }
        
        public static MvcHtmlString TelerikReport(this HtmlHelper htmlHelper, object  value, object htmlAttributes )
        {
            NoServerFormPage page = new NoServerFormPage();
            RadMvcScriptManager mvcScriptManager = new RadMvcScriptManager();
            mvcScriptManager.EnableViewState = false;
            page.Controls.Add(mvcScriptManager);
            RadStyleSheetManager radStyleSheetManager = new RadStyleSheetManager();
            page.Controls.Add(radStyleSheetManager);

            ReportViewer reportViewer = new ReportViewer();
            reportViewer.ID = "whoCares";
            reportViewer.Height = 890;
            reportViewer.Width = 700;
            
            reportViewer.ToolbarVisible = true;
            reportViewer.Report = new Ntk.Reports.Racun();
            ((Telerik.Reporting.Report)reportViewer.Report).ReportParameters["ID"].Value = value;
            reportViewer.Resources.CurrentPageToolTip = "Trenutna stran";
            reportViewer.Resources.ExportButtonText = "Izvozi";
            reportViewer.Resources.ExportSelectFormatText = "Izberi format za izvoz";
            reportViewer.Resources.ExportToolTip = "Izvoz";
            reportViewer.Resources.FirstPageToolTip = "prva stran";
            reportViewer.Resources.LabelOf = "od";
            reportViewer.Resources.LastPageToolTip = "Zadnja stran";
            reportViewer.Resources.NextPageToolTip = "naslednja stran";
            reportViewer.Resources.PreviousPageToolTip = "prejšnja stran";
            reportViewer.Resources.PrintToolTip = "Natisni";
            reportViewer.Resources.ProcessingReportMessage = "Nalagam...";
            reportViewer.Resources.RefreshToolTip = "Osveži";
            

            page.Controls.Add(reportViewer);
            StringWriter output = new StringWriter();
            HttpContext.Current.Server.Execute(page, output, false);

            return MvcHtmlString.Create(output.ToString());
        }


Telerik ASP.NET AJAX Controls in MVC project

clock August 18, 2010 23:37 by author Rok Bermež

If we want to use Telerik ASP.NET AJAX controls in MVC project, we must also use either ScriptManager or RadScriptManager. But since neither works very well here is more MVC friendly solution:

 public class RadMvcScriptManager : RadScriptManager
{
static string JavaScriptBlockFormat = @"<script type=""text/javascript"">
//<![CDATA[
{0}
//]]>
</script>"
;

protected override void Render(HtmlTextWriter writer)
{
foreach (RegisteredScript script in GetRegisteredClientScriptBlocks())
{
if (HttpContext.Current.Items[script.Key] == null)
{
HttpContext.Current.Items[script.Key] = true;

if (script.ScriptType == RegisteredScriptType.ClientScriptInclude)
{
writer.WriteLine(String.Format(@"<script type=""text/javascript"" src=""{0}""></script>",
HttpUtility.HtmlEncode(script.Url)));
}
}
}



if (HttpContext.Current.Items["AppInitialize"] == null)
{
Page.Items["AppInitialize"] = true;
writer.WriteLine(
String.Format(
JavaScriptBlockFormat,
@"if(typeof(Sys) != ""undefined""){
$addHandler(window, "
"load"", function(){Sys.Application.initialize();}); }
else { throw new Error("
"Microsoft ASP.NET AJAX cannot be initialized!"")}"));
}

StringBuilder builder = new StringBuilder();

if (HasReflectionPermission())
{
SerializeScriptsForScriptControls(Page, builder);
}

string scriptContent = builder.ToString();
if (!String.IsNullOrEmpty(scriptContent))
{
writer.WriteLine(String.Format(
JavaScriptBlockFormat,
String.Format("Sys.Application.add_init(function(){{{0}}});", scriptContent)));
}
}

internal void SerializeScriptsForScriptControls(Control control, StringBuilder builder)
{
if (control is IScriptControl && control.Visible)
{
IEnumerable<ScriptDescriptor> descriptors = ((IScriptControl)control).GetScriptDescriptors();
if (descriptors != null)
{
foreach (ScriptDescriptor descriptor in descriptors)
{
SerializeScriptControlDescriptor(descriptor, builder);
}
}
}

if (control.HasControls())
{
foreach (Control child in control.Controls)
{
SerializeScriptsForScriptControls(child, builder);
}
}
}

internal void SerializeScriptControlDescriptor(ScriptDescriptor descriptor, StringBuilder builder)
{
MethodInfo getScriptInfo = descriptor.GetType().GetMethod(
"GetScript",
BindingFlags.Instance | BindingFlags.NonPublic);
if (getScriptInfo != null)
{
string script = (string)getScriptInfo.Invoke(descriptor, new object[] { });
builder.AppendLine(script);
}
}

internal static bool HasReflectionPermission()
{
try
{
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand();
return true;
}
catch (SecurityException)
{
return false;
}
}
}


About the author

Rok Bermež is Slovenian Windows Azure MVP, he works as a Software Engineer and Microsoft Certified Trainer at Kompas Xnet. His primary interests include cloud computing and web development. With extensive experience in development and architecture he participated in many projects and since the CTP release of Windows Azure much of those projects are based on Windows Azure platform. Rok has been delivering courses, writing code and speaking at conferences and community events on Microsoft technologies for the last couple of years. You can also find him on Twitter (@Rok_B).

Month List

Sign In