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
Yes , i have the same problem that mike have , please help me to solve this problem !?
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
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
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
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 !
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
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
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