Is it possible to put custom properties in a directory with Sardine? - webdav

I am trying to put some custom property in a directory WebDAV, but it is only working with files.
I am using Sardine library with Jackrabbit, example:
public static void main(String[] args) throws IOException {
Sardine sardine = SardineFactory.begin();
String someUrl = "http://localhost:8080/repository/default/temp/";
int depthInfiniteRecursion = -1;
// 1. Set custom properties on a resource:
List<DavResource> resourcesBefore = sardine.list(someUrl, depthInfiniteRecursion);
for (DavResource resource : resourcesBefore) {
Map<QName, String> addProps = new LinkedHashMap<>();
QName author = new QName("http://luankevinferreira.github.io", "author", "playground");
addProps.put(author, "Luan K. Ferreira");
sardine.patch(resource.getHref().toURL().toString(), addProps);
}
// 2. Retrieve custom properties on a resource:
List<DavResource> resources = sardine.list(someUrl, depthInfiniteRecursion);
for (DavResource resource : resources) {
Map<String, String> customProps = resource.getCustomProps();
// Use custom properties...
System.out.println("Resource: " + resource);
System.out.println("Properties: " + customProps);
}
}
The result of the execution with one directory and one file is:
Resource: /repository/default/temp/
Properties: {createdBy=admin, created=2018-08-21T18:37:10.446Z, iscollection=1}
Resource: /repository/default/temp/test.txt
Properties: {author=Luan K. Ferreira, iscollection=0}
Is there anyway to put the property in the directory?

Related

How do you hand over files to the user?

in a #WASM / #UNO-platform project, how do you hand over files to the user?
In my case I’m generation locally a PDF and had to download it or display it in the browser.
Any clue?
Regards,
Michael
There's no API to do that directly, yet. But you can create a data: url on an anchor (a) HTML element.
For this you'll need to create some JavaScript. Here's how you can do it:
IMPORTANT: following code will only work with very recent version of Uno.UI. Version starting with v3.0.0-dev.949+
Create a ContentControl for the <a> tag
[HtmlElement("a")]
public partial class WasmDownload : ContentControl
{
public static readonly DependencyProperty MimeTypeProperty = DependencyProperty.Register(
"MimeType", typeof(string), typeof(WasmDownload), new PropertyMetadata("application/octet-stream", OnChanged));
public string MimeType
{
get => (string) GetValue(MimeTypeProperty);
set => SetValue(MimeTypeProperty, value);
}
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register(
"FileName", typeof(string), typeof(WasmDownload), new PropertyMetadata("filename.bin", OnChanged));
public string FileName
{
get => (string) GetValue(FileNameProperty);
set => SetValue(FileNameProperty, value);
}
private Memory<byte> _content;
public void SetContent(Memory<byte> content)
{
_content = content;
Update();
}
private static void OnChanged(DependencyObject dependencyobject, DependencyPropertyChangedEventArgs args)
{
if (dependencyobject is WasmDownload wd)
{
wd.Update();
}
}
private void Update()
{
if (_content.Length == 0)
{
this.ClearHtmlAttribute("href");
}
else
{
var base64 = Convert.ToBase64String(_content.ToArray());
var dataUrl = $"data:{MimeType};base64,{base64}";
this.SetHtmlAttribute("href", dataUrl);
this.SetHtmlAttribute("download", FileName);
}
}
}
Use it in Your XAML Page
<myControls:WasmDownload FileName="test.txt" x:Name="download">
Click here to download
</myControls:WasmDownload>
Note you can put anything in the content of your control, as any other XAML ContentControl.
Set the File Content in Code Behind
Loaded += (sender, e) =>
{
download.MimeType = "text/plain";
var bytes = Encoding.UTF8.GetBytes("this is the content");
download.SetContent(bytes);
};
Result
Direct support by Uno
There is a PR #3380 to add this feature to Uno natively for all platforms. You can also wait for it instead of doing custom way.
The PR for FileSavePicker has been merged and the feature is now available in package Uno.UI since version 3.0.0-dev.1353.

Custom Path to the DisplayTemplates folder [duplicate]

I have the following layout for my mvc project:
/Controllers
/Demo
/Demo/DemoArea1Controller
/Demo/DemoArea2Controller
etc...
/Views
/Demo
/Demo/DemoArea1/Index.aspx
/Demo/DemoArea2/Index.aspx
However, when I have this for DemoArea1Controller:
public class DemoArea1Controller : Controller
{
public ActionResult Index()
{
return View();
}
}
I get the "The view 'index' or its master could not be found" error, with the usual search locations.
How can I specify that controllers in the "Demo" namespace search in the "Demo" view subfolder?
You can easily extend the WebFormViewEngine to specify all the locations you want to look in:
public class CustomViewEngine : WebFormViewEngine
{
public CustomViewEngine()
{
var viewLocations = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/AnotherPath/Views/{0}.ascx"
// etc
};
this.PartialViewLocationFormats = viewLocations;
this.ViewLocationFormats = viewLocations;
}
}
Make sure you remember to register the view engine by modifying the Application_Start method in your Global.asax.cs
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
}
Now in MVC 6 you can implement IViewLocationExpander interface without messing around with view engines:
public class MyViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context) {}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
return new[]
{
"/AnotherPath/Views/{1}/{0}.cshtml",
"/AnotherPath/Views/Shared/{0}.cshtml"
}; // add `.Union(viewLocations)` to add default locations
}
}
where {0} is target view name, {1} - controller name and {2} - area name.
You can return your own list of locations, merge it with default viewLocations (.Union(viewLocations)) or just change them (viewLocations.Select(path => "/AnotherPath" + path)).
To register your custom view location expander in MVC, add next lines to ConfigureServices method in Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});
}
There's actually a lot easier method than hardcoding the paths into your constructor. Below is an example of extending the Razor engine to add new paths. One thing I'm not entirely sure about is whether the paths you add here will be cached:
public class ExtendedRazorViewEngine : RazorViewEngine
{
public void AddViewLocationFormat(string paths)
{
List<string> existingPaths = new List<string>(ViewLocationFormats);
existingPaths.Add(paths);
ViewLocationFormats = existingPaths.ToArray();
}
public void AddPartialViewLocationFormat(string paths)
{
List<string> existingPaths = new List<string>(PartialViewLocationFormats);
existingPaths.Add(paths);
PartialViewLocationFormats = existingPaths.ToArray();
}
}
And your Global.asax.cs
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ExtendedRazorViewEngine engine = new ExtendedRazorViewEngine();
engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.cshtml");
engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.vbhtml");
// Add a shared location too, as the lines above are controller specific
engine.AddPartialViewLocationFormat("~/MyThemes/{0}.cshtml");
engine.AddPartialViewLocationFormat("~/MyThemes/{0}.vbhtml");
ViewEngines.Engines.Add(engine);
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
One thing to note: your custom location will need the ViewStart.cshtml file in its root.
If you want just add new paths, you can add to the default view engines and spare some lines of code:
ViewEngines.Engines.Clear();
var razorEngine = new RazorViewEngine();
razorEngine.MasterLocationFormats = razorEngine.MasterLocationFormats
.Concat(new[] {
"~/custom/path/{0}.cshtml"
}).ToArray();
razorEngine.PartialViewLocationFormats = razorEngine.PartialViewLocationFormats
.Concat(new[] {
"~/custom/path/{1}/{0}.cshtml", // {1} = controller name
"~/custom/path/Shared/{0}.cshtml"
}).ToArray();
ViewEngines.Engines.Add(razorEngine);
The same applies to WebFormEngine
Instead of subclassing the RazorViewEngine, or replacing it outright, you can just alter existing RazorViewEngine's PartialViewLocationFormats property. This code goes in Application_Start:
System.Web.Mvc.RazorViewEngine rve = (RazorViewEngine)ViewEngines.Engines
.Where(e=>e.GetType()==typeof(RazorViewEngine))
.FirstOrDefault();
string[] additionalPartialViewLocations = new[] {
"~/Views/[YourCustomPathHere]"
};
if(rve!=null)
{
rve.PartialViewLocationFormats = rve.PartialViewLocationFormats
.Union( additionalPartialViewLocations )
.ToArray();
}
Last I checked, this requires you to build your own ViewEngine. I don't know if they made it easier in RC1 though.
The basic approach I used before the first RC was, in my own ViewEngine, to split the namespace of the controller and look for folders which matched the parts.
EDIT:
Went back and found the code. Here's the general idea.
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
{
string ns = controllerContext.Controller.GetType().Namespace;
string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");
//try to find the view
string rel = "~/Views/" +
(
ns == baseControllerNamespace ? "" :
ns.Substring(baseControllerNamespace.Length + 1).Replace(".", "/") + "/"
)
+ controller;
string[] pathsToSearch = new string[]{
rel+"/"+viewName+".aspx",
rel+"/"+viewName+".ascx"
};
string viewPath = null;
foreach (var path in pathsToSearch)
{
if (this.VirtualPathProvider.FileExists(path))
{
viewPath = path;
break;
}
}
if (viewPath != null)
{
string masterPath = null;
//try find the master
if (!string.IsNullOrEmpty(masterName))
{
string[] masterPathsToSearch = new string[]{
rel+"/"+masterName+".master",
"~/Views/"+ controller +"/"+ masterName+".master",
"~/Views/Shared/"+ masterName+".master"
};
foreach (var path in masterPathsToSearch)
{
if (this.VirtualPathProvider.FileExists(path))
{
masterPath = path;
break;
}
}
}
if (string.IsNullOrEmpty(masterName) || masterPath != null)
{
return new ViewEngineResult(
this.CreateView(controllerContext, viewPath, masterPath), this);
}
}
//try default implementation
var result = base.FindView(controllerContext, viewName, masterName);
if (result.View == null)
{
//add the location searched
return new ViewEngineResult(pathsToSearch);
}
return result;
}
Try something like this:
private static void RegisterViewEngines(ICollection<IViewEngine> engines)
{
engines.Add(new WebFormViewEngine
{
MasterLocationFormats = new[] {"~/App/Views/Admin/{0}.master"},
PartialViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.ascx"},
ViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.aspx"}
});
}
protected void Application_Start()
{
RegisterViewEngines(ViewEngines.Engines);
}
Note: for ASP.NET MVC 2 they have additional location paths you will need to set for views in 'Areas'.
AreaViewLocationFormats
AreaPartialViewLocationFormats
AreaMasterLocationFormats
Creating a view engine for an Area is described on Phil's blog.
Note: This is for preview release 1 so is subject to change.
Most of the answers here, clear the existing locations by calling ViewEngines.Engines.Clear() and then add them back in again... there is no need to do this.
We can simply add the new locations to the existing ones, as shown below:
// note that the base class is RazorViewEngine, NOT WebFormViewEngine
public class ExpandedViewEngine : RazorViewEngine
{
public ExpandedViewEngine()
{
var customViewSubfolders = new[]
{
// {1} is conroller name, {0} is action name
"~/Areas/AreaName/Views/Subfolder1/{1}/{0}.cshtml",
"~/Areas/AreaName/Views/Subfolder1/Shared/{0}.cshtml"
};
var customPartialViewSubfolders = new[]
{
"~/Areas/MyAreaName/Views/Subfolder1/{1}/Partials/{0}.cshtml",
"~/Areas/MyAreaName/Views/Subfolder1/Shared/Partials/{0}.cshtml"
};
ViewLocationFormats = ViewLocationFormats.Union(customViewSubfolders).ToArray();
PartialViewLocationFormats = PartialViewLocationFormats.Union(customPartialViewSubfolders).ToArray();
// use the following if you want to extend the master locations
// MasterLocationFormats = MasterLocationFormats.Union(new[] { "new master location" }).ToArray();
}
}
Now you can configure your project to use the above RazorViewEngine in Global.asax:
protected void Application_Start()
{
ViewEngines.Engines.Add(new ExpandedViewEngine());
// more configurations
}
See this tutoral for more info.
I did it this way in MVC 5. I didn't want to clear the default locations.
Helper Class:
namespace ConKit.Helpers
{
public static class AppStartHelper
{
public static void AddConKitViewLocations()
{
// get engine
RazorViewEngine engine = ViewEngines.Engines.OfType<RazorViewEngine>().FirstOrDefault();
if (engine == null)
{
return;
}
// extend view locations
engine.ViewLocationFormats =
engine.ViewLocationFormats.Concat(new string[] {
"~/Views/ConKit/{1}/{0}.cshtml",
"~/Views/ConKit/{0}.cshtml"
}).ToArray();
// extend partial view locations
engine.PartialViewLocationFormats =
engine.PartialViewLocationFormats.Concat(new string[] {
"~/Views/ConKit/{0}.cshtml"
}).ToArray();
}
}
}
And then in Application_Start:
// Add ConKit View locations
ConKit.Helpers.AppStartHelper.AddConKitViewLocations();

Spring MVC Rest unable to return JPEG with "could not find acceptable representation error"

I have a spring-boot app acting as a image server. I POST an image to be persisted to mongodb. I then retrieve it, resize and return it.
Here is the project configuration:
#Configuration
public class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
}
And here is the endpoint:
#RequestMapping(value = "images/{filename}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<BufferedImage> getSizedImage(#PathVariable String filename, #RequestParam int width, #RequestParam int height) throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
GridFSDBFile savedFile = mongoFileService.getStore( filename );
if ( savedFile != null ) {
try {
BufferedImage image = ImageIO.read( savedFile.getInputStream() );
image = resize( image, Method.SPEED, width, height, Scalr.OP_ANTIALIAS );
LOGGER.info("Returning Filename " + savedFile.getFilename() + " sized to " + width + " X " + height);
return new ResponseEntity<BufferedImage>(image, headers, HttpStatus.OK);
} catch ( Exception ex ) {
ex.printStackTrace();
LOGGER.error( "Error sizing file " + filename + ": " + ex.getMessage() );
return new ResponseEntity<BufferedImage>(null, headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
} else {
LOGGER.error( "Could not find requested file " + filename );
return new ResponseEntity<BufferedImage>(null, headers, HttpStatus.NOT_FOUND);
}
}
The image is retrieved and resized (I can actually preview when debugging in IntelliJ). But when it is returned, I get the following error:
Controller [org.springframework.boot.autoconfigure.web.BasicErrorController]
Method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:195)
And I see this in the logs:
Method [error] returned [<406 Not Acceptable,{timestamp=Sat Aug 22 11:05:59 MDT 2015, status=406, error=Not Acceptable, exception=org.springframework.web.HttpMediaTypeNotAcceptableException, message=Could not find acceptable representation, path=/images/1440263145562_profile_04132015.PNG},{}>]
2015-08-22 11:05:59.711 DEBUG 2478 --- [0.1-3000-exec-3] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Sat Aug 22 11:05:59 MDT 2015, status=406, error=Not Acceptable, exception=org.springframework.web.HttpMediaTypeNotAcceptableException, message=Could not find acceptable representation, path=/images/1440263145562_profile_04132015.PNG}] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#5bf1ba3a]
2015-08-22 11:05:59.711 DEBUG 2478 --- [0.1-3000-exec-3] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
I have tried with & without the #ResponseBody and it doesn't appear to make a difference either. I have the produces and content type set correctly (I think).
I added these converters (although I thought SpringBoot provided these), but to no avail:
#Configuration
public class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
#Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter(){
ByteArrayHttpMessageConverter bam = new ByteArrayHttpMessageConverter();
List<org.springframework.http.MediaType> mediaTypes = new LinkedList<MediaType>();
mediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON);
mediaTypes.add(org.springframework.http.MediaType.IMAGE_JPEG);
mediaTypes.add(org.springframework.http.MediaType.IMAGE_PNG);
mediaTypes.add(org.springframework.http.MediaType.IMAGE_GIF);
mediaTypes.add(org.springframework.http.MediaType.TEXT_PLAIN);
bam.setSupportedMediaTypes(mediaTypes);
return bam;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter mapper = new MappingJackson2HttpMessageConverter();
converters.add(mapper);
converters.add(byteArrayHttpMessageConverter());
super.configureMessageConverters(converters);
}
}
I hope someone can see what is causing this issue.
Try this piece of code
#RequestMapping("/sparklr/photos/{id}")
public ResponseEntity<BufferedImage> photo(#PathVariable String id) throws Exception {
InputStream photo = sparklrService.loadSparklrPhoto(id);
if (photo == null) {
throw new UnavailableException("The requested photo does not exist");
}
BufferedImage body;
MediaType contentType = MediaType.IMAGE_JPEG;
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
if (imageReaders.hasNext()) {
ImageReader imageReader = imageReaders.next();
ImageReadParam irp = imageReader.getDefaultReadParam();
imageReader.setInput(new MemoryCacheImageInputStream(photo), true);
body = imageReader.read(0, irp);
} else {
throw new HttpMessageNotReadableException("Could not find javax.imageio.ImageReader for Content-Type ["
+ contentType + "]");
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<BufferedImage>(body, headers, HttpStatus.OK);
}
EDIT:
We have to configure MessageConverter
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new BufferedImageHttpMessageConverter());
}
Here I have Content Negotiator like this
#Bean
public ContentNegotiatingViewResolver contentViewResolver() throws Exception {
ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON);
contentViewResolver.setContentNegotiationManager(contentNegotiationManager.getObject());
contentViewResolver.setDefaultViews(Arrays.<View> asList(new MappingJackson2JsonView()));
return contentViewResolver;
}
I think the message inside your logs can clear your doubts. Have a close look at your logs and comment me again
I think the problem is that none of the registered message converters knows how to write a BufferedImage to the response in the format dictated by the accept header. Try registering your own message converter that knows how to write out a BufferedImage in the requested format.

Problems while trying to add an xml file to Alfresco

Am facing an issue with Alfresco and honestly am not expert with this type of technology:
the idea is to add an xml file under a folder
the code is like that:
//with the static values are:
public static final String SUSPENDRE_DESUSPENDRE_CONTENT_NAME = "suspendreDesuspendre";
private static final String SUSPENDRE_DESUSPENDRE_CONTENT_TYPE = "text/xml";
private static final String SUSPENDRE_DESUSPENDRE_CONTENT_ENCODING = "UTF-8";
private static final ContentFormat SUSPENDRE_DESUSPENDRE_CONTENT_FORMAT = new ContentFormat(SUSPENDRE_DESUSPENDRE_CONTENT_TYPE,SUSPENDRE_DESUSPENDRE_CONTENT_ENCODING);
private static final byte[] SUSPENDRE_DESUSPENDRE_CONTENT_INITIAL_BYTES = "<?xml //version=\"1.0\" encoding=\"UTF-8\"?><suspendreDesuspendre></suspendreDesuspendre>".getBytes();
#Override
public void createOrUpdateHisSuspendre(ContractBean contractbean,SuspendreDesuspendreEntree suspendreDesuspendreEntree) throws Exception
{
String parentUuid=contractbean.getUuid();
contractDAO.createAlfrescoContent(parentUuid, SUSPENDRE_DESUSPENDRE_CONTENT_NAME, SUSPENDRE_DESUSPENDRE_CONTENT_INITIAL_BYTES, SUSPENDRE_DESUSPENDRE_CONTENT_FORMAT);
}
public Reference createAlfrescoContent(String folderUuid, String contentName,byte[] contentBytes,ContentFormat contentFormat)throws RepositoryFault, RemoteException {
ParentReference parentReference = new ParentReference(new Store(Constants.WORKSPACE_STORE, "SpacesStore"), folderUuid, null, Constants.ASSOC_CONTAINS, "{" + Constants.NAMESPACE_CONTENT_MODEL + "}" + contentName);
NamedValue[] properties = new NamedValue[]{Utils.createNamedValue(Constants.PROP_NAME, contentName)};
CMLCreate create = new CMLCreate("1", parentReference, null, null, null,
Constants.TYPE_CONTENT, properties);
CML cml = new CML();
cml.setCreate(new CMLCreate[]{create});
UpdateResult[] result = WebServiceFactory.getRepositoryService().update(cml);
Reference newContentNode = result[0].getDestination();
Content content = WebServiceFactory.getContentService().write(newContentNode, Constants.PROP_CONTENT, contentBytes, contentFormat);
return content.getNode();
}
the error is:
The association source type is incorrect:
Source Node: workspace://SpacesStore/d4ffbff4-6bd6-4945-948e-2c16c1990cb9
Association: Association[ class=ClassDef[name={http://www.alfresco.org/model/content/1.0}folder], name={http://www.alfresco.org/model/content/1.0}contains, target class={http://www.alfresco.org/model/system/1.0}base, source role=null, target role=null]
Required Source Type: {http://www.alfresco.org/model/content/1.0}folder
Actual Source Type: {com.genia.cnas.alfresco.model}contratDefenseur

Create the own VirtualPathProvider in MVC4?

I'm suffering trying to get some views from a library to the main project. I was starting to read about creating your own VirtualPathProvider implementation here: Using VirtualPathProvider to load ASP.NET MVC views from DLLs
I had to set my view = EmbbebedResource to get the resource from the library. But now is throwing another error.
In the header of my partial view I had the following:
#model Contoso.ExercisesLibrary.AbsoluteArithmetic.Problem1
And the error says: External component has thrown an exception. c:\Users\Oscar\AppData\Local\Temp\Temporary ASP.NET Files\root\4f78c765\7f9a47c6\App_Web_contoso.exerciseslibrary.absolutearithmetic.view1.cshtml.38e14c22.y-yjyt6g.0.cs(46): error CS0103: The name 'model' does not exist in the current context
I don't know why the compiler tells that cannot recognized my model. When I'm in design mode, I can see the compiler that the check is all right.
Check the image
What am I doing wrong o what am I missing?
Thanks in advance.
Try adding an #inherits directive to the top of your razor view:
#inherits System.Web.Mvc.WebViewPage
#model Contoso.ExercisesLibrary.AbsoluteArithmetic.Problem1
The reason you need this is because your view comes from an embedded resource and not from the standard ~/Views location. And as you know inside ~/Views there's a file called web.config. And inside this file there's a pageBaseType="System.Web.Mvc.WebViewPage" directive indicating that all Razor files inside ~/Views should inherit from this base type. But since your view is now coming from an unknown location you have nowhere specified that it should be a System.Web.Mvc.WebViewPage. And all the MVC specific stuff such as models, HTML helpers, ... are defined in this base class.+
I faced this issue "The name 'model' does not exist in the current context". What I did was added same "areas" folder structure (from my embedded mvc project) to my main MVC project (Areas/AnualReports/Views/) and copied web.config (default web.config from views folder, not the one from root) to Views folder which solved the issue. I am not sure this will work in your case.
Update:
Adding web.config (from views folder) to root "areas" folder in main MVC project also works.
I have the same problem as you so after all searches I got working solution
Create your own WebViewPage based abstract class (generic for model and non generic)
public abstract class MyOwnViewPage<TModel> : WebViewPage<TModel> { }
public abstract class MyOwnViewPage : WebViewPage { }
Next create VirtualFile based class or embedded view's
class AssemblyResourceFile : VirtualFile
{
private readonly IDictionary<string, Assembly> _nameAssemblyCache;
private readonly string _assemblyPath;
private readonly string _webViewPageClassName;
public string LayoutPath { get; set; }
public string ViewStartPath { get; set; }
public AssemblyResourceFile(IDictionary<string, Assembly> nameAssemblyCache, string virtualPath) :
base(virtualPath)
{
_nameAssemblyCache = nameAssemblyCache;
_assemblyPath = VirtualPathUtility.ToAppRelative(virtualPath);
LayoutPath = "~/Views/Shared/_Layout.cshtml";
ViewStartPath = "~/Views/_ViewStart.cshtml";
_webViewPageClassName = typeofMyOwnViewPage).ToString();
}
// Please change Open method for your scenario
public override Stream Open()
{
string[] parts = _assemblyPath.Split(new[] { '/' }, 4);
string assemblyName = parts[2];
string resourceName = parts[3].Replace('/', '.');
Assembly assembly;
lock (_nameAssemblyCache)
{
if (!_nameAssemblyCache.TryGetValue(assemblyName, out assembly))
{
var assemblyPath = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
assembly = Assembly.LoadFrom(assemblyPath);
_nameAssemblyCache[assemblyName] = assembly;
}
}
Stream resourceStream = null;
if (assembly != null)
{
resourceStream = assembly.GetManifestResourceStream(resourceName);
if (resourceName.EndsWith(".cshtml"))
{
//the trick is here. We must correct our embedded view
resourceStream = CorrectView(resourceName, resourceStream);
}
}
return resourceStream;
}
public Stream CorrectView(string virtualPath, Stream stream)
{
var reader = new StreamReader(stream, Encoding.UTF8);
var view = reader.ReadToEnd();
stream.Close();
var ourStream = new MemoryStream();
var writer = new StreamWriter(ourStream, Encoding.UTF8);
var modelString = "";
var modelPos = view.IndexOf("#model");
if (modelPos != -1)
{
writer.Write(view.Substring(0, modelPos));
var modelEndPos = view.IndexOfAny(new[] { '\r', '\n' }, modelPos);
modelString = view.Substring(modelPos, modelEndPos - modelPos);
view = view.Remove(0, modelEndPos);
}
writer.WriteLine("#using System.Web.Mvc");
writer.WriteLine("#using System.Web.Mvc.Ajax");
writer.WriteLine("#using System.Web.Mvc.Html");
writer.WriteLine("#using System.Web.Routing");
var basePrefix = "#inherits " + _webViewPageClassName;
if (virtualPath.ToLower().Contains("_viewstart"))
{
writer.WriteLine("#inherits System.Web.WebPages.StartPage");
}
else if (modelString == "#model object")
{
writer.WriteLine(basePrefix + "<dynamic>");
}
else if (!string.IsNullOrEmpty(modelString))
{
writer.WriteLine(basePrefix + "<" + modelString.Substring(7) + ">");
}
else
{
writer.WriteLine(basePrefix);
}
writer.Write(view);
writer.Flush();
ourStream.Position = 0;
return ourStream;
}
}
Next create VirtualPathProvider based class (modify it for your purposes)
public class AssemblyResPathProvider : VirtualPathProvider
{
private readonly Dictionary<string, Assembly> _nameAssemblyCache;
private string _layoutPath;
private string _viewstartPath;
public AssemblyResPathProvider(string layout, string viewstart)
{
_layoutPath = layout;
_viewstartPath = viewstart;
_nameAssemblyCache = new Dictionary<string, Assembly>(StringComparer.InvariantCultureIgnoreCase);
}
private bool IsAppResourcePath(string virtualPath)
{
string checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
bool bres1 = checkPath.StartsWith("~/App_Resource/",
StringComparison.InvariantCultureIgnoreCase);
bool bres2 = checkPath.StartsWith("/App_Resource/",
StringComparison.InvariantCultureIgnoreCase);
//todo: fix this
if (checkPath.EndsWith("_ViewStart.cshtml"))
{
return false;
}
if (checkPath.EndsWith("_ViewStart.vbhtml"))
{
return false;
}
return ((bres1 || bres2));
}
public override bool FileExists(string virtualPath)
{
return (IsAppResourcePath(virtualPath) ||
base.FileExists(virtualPath));
}
public override VirtualFile GetFile(string virtualPath)
{
if (IsAppResourcePath(virtualPath))
{
// creating AssemblyResourceFile instance
return new AssemblyResourceFile(_nameAssemblyCache, virtualPath,_layoutPath,virtualPath);
}
return base.GetFile(virtualPath);
}
public override CacheDependency GetCacheDependency(
string virtualPath,
IEnumerable virtualPathDependencies,
DateTime utcStart)
{
if (IsAppResourcePath(virtualPath))
{
return null;
}
return base.GetCacheDependency(virtualPath,
virtualPathDependencies, utcStart);
}
}
At last register your AssemblyResPathProvider in global.asax
string _layoutPath = "~/Views/Shared/_Layout.cshtml";
string _viewstarPath = "~/Views/_ViewStart.cshtml";
HostingEnvironment.RegisterVirtualPathProvider(new AssemblyResPathProvider(_layoutPath,_viewstarPath));
This is not ideal solution but its working for me good. Cheers!
In my case, the solution was to make the virtual Path start with "~Views/" - just like any normal view.
Not working: ~/VIRTUAL/Home/Index.cshtml
Working: ~/Views/VIRTUAL/Home/Index.cshtml
I think, this has to do with the web.config lying around in ~/Views and defining a lot of stuff for the views. Maybe anybody can give more information.
Hope that helps anyway.

Resources