This is a migrated thread and some comments may be shown as answers.

ScriptRegistrar Embedded Resource in Portable Area

8 Answers 101 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Mike
Top achievements
Rank 1
Mike asked on 21 Jan 2011, 11:41 PM
I am trying to use the ScriptRegistrar from the Telerik MVC Extensions. I have used it for a while on different projects, but this is the first time that I am trying to use it with an MVC Portable Area. Ultimately, I have created an extension method which allows me to add the scripts that are needed from the portable area. However, when it tries to Render them, I get an IO error that the file is not found.

To give a bit of knowledge on Portable Areas, the script resource needs to be embedded and the routes need to be set up correctly (both of which are the case). It seems that the ScriptRegistrar when rendering is not going through the normal routes.

Have you had any similiar problems or do you have a way to solve this?

Thanks,
Mike

8 Answers, 1 is accepted

Sort by
0
ahmad
Top achievements
Rank 1
answered on 30 Jul 2011, 05:16 PM
Hi telerik

Yes , i have the same problem that mike have , please help me to solve this problem !?
0
Mike
Top achievements
Rank 1
answered on 01 Aug 2011, 02:01 AM
Ahmad and Telerik,

I solved this problem on the weekend after posting. How I solved it was to look in the Telerik code and figure out what was going on and where I could intercept what was happening. First off, Telerik uses a Container, so it is easy to write your own implementation of an interface and then on Application Start inject your version instead of theirs. So, with Telerik's implementation, there are two problem areas that need fixed. They both go under the assumption that it is looking for a file, versus an embedded resource in an assembly.

First thing I did was to create an implementation for IWebAssetLocator. You will need to implement all the methods the same way as Telerik's except this one:

private string ProbePath(string virtualPath, string version, IEnumerable<string> extensions)
{
    foreach (var modifier in new[] { version, "" })
    {
        foreach (var extension in extensions)
        {
            var changedPath = Path.ChangeExtension(virtualPath, extension);
 
            string result = null;
 
            if (TryPath(changedPath, modifier, out result))
            {
                return result;
            }
        }
    }
    return virtualPath;
}

before, it would throw an error here if the file did not exist, now I just return the virtual path.

Then you will need to implement IVirtualPathProvider and leave all the methods the same as Telerik's except for this one:
public string ReadAllText(string virtualPath)
{
    string path = VirtualPathUtility.IsAppRelative(virtualPath) ?
                  VirtualPathUtility.ToAbsolute(virtualPath) :
                  virtualPath;
 
    // Try the file system first.
    if (FileExists(path))
    {
        using (var stream = VirtualPathProvider.OpenFile(path))
        {
            using (var streamReader = new StreamReader(stream))
            {
                return streamReader.ReadToEnd();
            }
        }
    }
 
    var currentRequest = HttpContext.Current.Request;
    var url = string.Format("{0}://{1}{2}", currentRequest.Url.Scheme, currentRequest.Url.Host, path);
 
    WebResponse response = null;
 
    try
    {
        var request = (HttpWebRequest)WebRequest.Create(url);
        request.AllowAutoRedirect = true;
 
        // Required to avoid triggering authentication when calling a JavaScriptView
        request.Headers["Cookie"] = currentRequest.Headers["Cookie"];
 
        ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
        response = request.GetResponse();
 
        using (var stream = response.GetResponseStream())
        {
            using (var streamReader = new StreamReader(stream))
            {
                return streamReader.ReadToEnd();
            }
        }
    }
    catch (WebException e)
    {
        if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.NotFound)
        {
            throw new HttpException(string.Format("{0} not found", url));
        }
        else
        {
            throw;
        }
    }
    finally
    {
        ServicePointManager.ServerCertificateValidationCallback -= ValidateRemoteCertificate;
        if (response != null) { response.Close(); }
    }
}
 
public static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
{
    return Convert.ToBoolean(ConfigurationManager.AppSettings["IgnoreSslErrors"]) || policyErrors == SslPolicyErrors.None;
}

This is where all the magic happens. It basically looks for the file first, if it exists, then it pulls it. If it doesn't then it makes a request using the route. It also handles https. This was a combined effort from a team I was on and it took us a few shots to get everything the way we wanted. I have also included a ValidateRemoteCertificates method that basically handles certs.

Finally, add it to the Application_Start with something like this:
DI.Current.Register<IVirtualPathProvider>(() => new RMTVirtualPathProviderWrapper());
DI.Current.Register<IWebAssetLocator, ICacheFactory, IVirtualPathProvider, IWebAssetExtensions>((cacheFactory, provider, extensions) =>
    new RMTWebAssetLocator(cacheFactory.Create("locator"), provider, extensions));

This seems to be working for portable areas and I hope that maybe Telerik can throw me a bone for giving this answer. I have been holding off for quite some time giving this code, since Portable Areas are a concept that a lot have not used yet. I however use them in more than one project and figure that this needs to make it into Telerik's code base sometime sooner rather than later. I am sure that there are improvements that can be made, but at least there is a starting point.

Please let me know if you have any questions.

Mike Moser
River Moss Technologies
0
ahmad
Top achievements
Rank 1
answered on 01 Aug 2011, 06:53 AM
Hi Mike

first of all , very thanks from your help .

i have problem in implement class IWebAssetLocator , i try to do , but in  Application_Start section the custom WebAssetLocator can't have constructor like this : new RMTWebAssetLocator(cacheFactory.Create("locator"), provider, extensions));
i implement this class :

public class CuWebAssetLocator : IWebAssetLocator
    {
        public string Locate(string virtualPath, string version)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        private string ProbePath(string virtualPath, string version, IEnumerable<string> extensions)
        {
            foreach (var modifier in new[] { version, "" })
            {
                foreach (var extension in extensions)
                {
                    var changedPath = Path.ChangeExtension(virtualPath, extension);
 
                    string result = null;
 
                    if (TryPath(changedPath, modifier, out result))
                    {
                        return result;
                    }  
                }
            }
            return virtualPath;
        }
 
        private bool TryPath(string changedPath, string modifier, out string result)
        {
            throw new NotImplementedException();
        }
 
    }

and CuVirtualPathProvider for IVirtualPathProvider .

public class CuVirtualPathProvider : IVirtualPathProvider
    {
        public bool DirectoryExists(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public bool FileExists(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public string GetDirectory(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public string GetFile(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public string GetExtension(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public string CombinePaths(string basePath, string relativePath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public string ReadAllText(string virtualPath)
        {
            string path = VirtualPathUtility.IsAppRelative(virtualPath) ?
                  VirtualPathUtility.ToAbsolute(virtualPath) :
                  virtualPath;
 
            // Try the file system first.
            if (FileExists(path))
            {
                using (Stream st= CuVirtualPathProvider.OpenFile(path))
                {
                    using (var streamReader = new StreamReader(st))
                    {
                        return streamReader.ReadToEnd();
                    }
                }
            }
            var currentRequest = HttpContext.Current.Request;
            var url = string.Format("{0}://{1}{2}", currentRequest.Url.Scheme, currentRequest.Url.Host, path);
 
            WebResponse response = null;
 
            try
            {
                var request = (HttpWebRequest)WebRequest.Create(url);
                request.AllowAutoRedirect = true;
 
                // Required to avoid triggering authentication when calling a JavaScriptView
                request.Headers["Cookie"] = currentRequest.Headers["Cookie"];
 
                ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
                response = request.GetResponse();
 
                using (var stream = response.GetResponseStream())
                {
                    using (var streamReader = new StreamReader(stream))
                    {
                        return streamReader.ReadToEnd();
                    }
                }
            }
            catch (WebException e)
            {
                if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.NotFound)
                {
                    throw new HttpException(string.Format("{0} not found", url));
                }
                else
                {
                    throw;
                }
            }
            finally
            {
                ServicePointManager.ServerCertificateValidationCallback -= ValidateRemoteCertificate;
                if (response != null) { response.Close(); }
            }
        }
   
        private static Stream OpenFile(string path)
        {
            Stream strem = new FileStream(path, FileMode.Open);
            return strem;
        }
 
        public static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
        {
            return Convert.ToBoolean(ConfigurationManager.AppSettings["IgnoreSslErrors"]) || policyErrors == SslPolicyErrors.None;
        }
 
 
        public string ToAbsolute(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
        public string AppendTrailingSlash(string virtualPath)
        {
            // TODO: Implement this method
            throw new NotImplementedException();
        }
 
 
    }

i am sure that don't implement these class correctly , also i can't know how you implement this method "TryPath"

if you can attach sample project , i thank you very much , and big help for me that beginner in MVC .

best regards
Ahmad
0
Atanas Korchev
Telerik team
answered on 01 Aug 2011, 08:01 AM
Hello Ahmad,

 I am not sure why you need to implement a custom IWebAssetLocator. Is there a chance to provide a sample project which does not work with the default ScriptRegistrar implementation?

Regards,
Atanas Korchev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

0
ahmad
Top achievements
Rank 1
answered on 01 Aug 2011, 10:39 AM
Hi Atanas

thanks for quick reply , i create many sample and see ScriptRegistrar works fine , but i found why does not work on my project ..

if you create New Area and edit MapRoute in RegisterArea like this :

public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "main_default",
                "{controller}/{action}/{id}",
                new { controller="home", action = "Index", id = UrlParameter.Optional }
            );
        }

ScriptRegistrar does not work in any Area .

i attach sample project with this problem .
this sample have 2 Area
1- Admin with this route map > admin/{controller}/{action}/{id}
2-main with this route map > /{controller}/{action}/{id}   (like above code)

you see that ScriptRegister does not work !
0
Mike
Top achievements
Rank 1
answered on 01 Aug 2011, 03:27 PM
Ahmad,

You need to pull the source code from Telerik from their MVC solution. You will then want to take a look at the WebAssetLocator and the VirtualPathProvider. Take the code from those or do some composition/inheritance and implement those methods correctly.

Mike
0
Mike
Top achievements
Rank 1
answered on 01 Aug 2011, 03:38 PM
Atanas,

I don't know if Telerik has ever done any Portable Areas, but this is a topic that a lot of people haven't delved into yet. What happens is that the Portable Area's dll gets loaded in and when the RegisterAllAreas is called in Application_Context, it finds the area with the PortableAreaRegistration on your Portable Area. Every javascript/css/View needs to be an embedded resource in that Portable Area so it gets put inside the dll. This is the part that Telerik Script Registrar/Style Sheet Registrar has troubles with. Since these are embedded resources, it cannot find them due to it always expecting a file that is content.

Mike
0
Atanas Korchev
Telerik team
answered on 02 Aug 2011, 07:25 AM
Hi Mike,

 Thank you for the clarification. Indeed the ScriptRegistrar does not support embedded resources at the time being. It seems that you have managed to implement that in your project. Is there any chance to attach a sample working project so other can benefit? You can submit it as a code library project. We will give you some Telerik points in exchange.

Regards,
Atanas Korchev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Tags
General Discussions
Asked by
Mike
Top achievements
Rank 1
Answers by
ahmad
Top achievements
Rank 1
Mike
Top achievements
Rank 1
Atanas Korchev
Telerik team
Share this question
or