How does RazorGenerator decide on the generated filename?

Nov 28, 2012 at 1:20 PM
Edited Nov 28, 2012 at 1:28 PM

On the face of it, the naming convention is simple - [FileName minus extension].generated.cs - but where there's an existing file of that name, a digit will be inserted before the extension, e.g. Result1.generated.cs

So far so normal, but I have a very slightly more complicated situation that is driving me very slightly mad. For some reason (dodgy Mesh synchronisation or dodgy SVN updating or something), I ended up with both Result.generated.cs and Result1.generated.cs, and no matter how many times I delete both of them and regenerate using the custom tool I seem to eventually end up with two files again, and a compiler error stemming from the duplicated class.

Now, to further test my sanity, I have Result.generated.cs and Result2.generated.cs. Yes, it's skipped past 1 (bored of that number) and gone straight to 2!

I double-checked that the files were gone from the disk and not just hidden in VS Solution Explorer.

So I have two questions: how do I stop this generated file duplication, and (to satisfy my curiosity) where is the tool storing the "fact" that there's already a 1 version of the file necessitating the move to the 2 version? Is there a repository of RazorGenerator filenames somewhere in my project?

 

Thanks!

Jon.

Coordinator
Nov 28, 2012 at 3:05 PM
Edited Nov 28, 2012 at 4:10 PM

Hmmm, I have not seen this issue. RazorGenerator doesn't store anything other than the files it generates. Do you have a small repro that demonstrates this issue?

thanks,
David 

Nov 28, 2012 at 3:13 PM

Hi David, thanks for the quick response.

I don't have a small repro at the moment because this is happening in a medium sized solution and it's not happening to all views so I'm not at all sure how I'd go about reproducing the effect.

Just now I noticed a second view developing a similar problem and wonder if it was anything to do with editing the view while the application was running - perhaps the generated file was in use and couldn't be modified? But that doesn't make much sense because surely the code's been precompiled by runtime so the generated source file shouldn't be needed?

I'll see if I can get the problem repeating in an empty MVC project and let you know if I have any success.

Regards,

Jon.

Coordinator
Nov 28, 2012 at 4:01 PM

Indeed, it's hard to see how the previous generated source could be in use from running the app. I would suggest working in a source control environment such that you can easily try the same thing multiple times while reverting to exactly the same state as before, to make sure that this is not somehow affected by some leftover artifacts.

Nov 28, 2012 at 4:03 PM

I've got a repro but I'm still scratching my head. It's a standard MVC4 Internet app and has all the usual dlls in the /bin so it's ~11MB zipped. I've put a copy at http://tempmon.jordansplace.co.uk/DeleteMe.zip if you want to grab it.

The effect isn't quite predictable so far. I had a more involved set of repro steps but while double-checking I found that I could break it much more easily. Steps I took from the vanilla solution:

  1. PM> Install-Package RazorGenerator.Mvc
  2. Set Custom Tool to RazorGenerator for Views\About.cshtml 
  3. Clicked "Run Custom Tool" after the generated file was created to see if a duplicate would be created. It wasn't.
  4. Edited About.cshtml
  5. Saved About.cshtml
  6. Duplicate created.

I'm very confused now because this certainly didn't happen *every* time I edited a view but I seem now to have the ability to create duplicates at will. The project I linked to above had a duplicate About.cshtml but no others. After zipping it up I tried the CustomTool->Edit->Save process on Contact.cshtml and Index.cshtml and both created duplicates. This is far worse than in my real application!

I tried again with a fresh solution and project and thought I'd cracked it - nothing went wrong until I edited and saved the file while the app was running, and thereafter something was permanently broken and I could create duplicates whether the app was running or not. That's almost true, but I now have a second project where I've performed the same actions on About.cshtml and Contact.cshtml and only About.cshtml is creating duplicates.

Sorry, I'm stumped! I'll let you know if I find anything else.

 

Nov 28, 2012 at 4:04 PM

Re your source control suggestion - I'll give that a go later on and get back to you. I have a deadline looming!

Coordinator
Nov 28, 2012 at 4:14 PM

Could you also specify what version of Visual Studio and of RazorGenerator you're using?

Nov 28, 2012 at 4:17 PM

Sure, RazorGenerator v1.4.0.0 and Visual Studio Professional 2012 (v11.0.50727.1)

Coordinator
Nov 28, 2012 at 4:17 PM

I was not able to repro with your solution, nor with a fresh one I created with the steps. Pretty strange!

Nov 28, 2012 at 4:21 PM

Very! Oh dear, maybe I've just picked up some bad karma from somewhere...

Did you try editing and saving the view while the app was running?

TBH, I'm not entirely surprised that you couldn't repro because even I can't reliably repro in my real project. I seem to have broken my test projects in a slightly more reliable way.

Coordinator
Nov 28, 2012 at 4:22 PM

Note that current RazorGenerator version is 1.5. Also, VS2012 has an update available. Definitely not saying that's the reason, but pointing out differences.

Nov 28, 2012 at 4:28 PM

Oh, I didn't specify a version when I installed from NuGet - do you recommend getting it direct from here (codeplex)? Wonder why NuGet's serving up the old version?

I saw the VS2012 update but there wasn't much in there of relevance to me so I put it off until later. I'll grab it this evening - even if it doesn't help it'll at least remove that suspicion.

Coordinator
Nov 28, 2012 at 4:52 PM
Edited Nov 28, 2012 at 4:53 PM

I think coming up with the number is part of the VS's single file generation code. All we do is tell it the extension we would like to use and VS figures out the name from the file name that's being generated. One thing you could do is edit the csproj and see if there are stray file with the DependsOn property set to your file. Or perhaps try disabling the SVN extension if you have that. 

That said, an alternative you could look at is going the msbuild route. Those files are never a part of the project so it might be a reasonable workaround if the problem persists 

Coordinator
Nov 28, 2012 at 4:56 PM

Oh, and when I referred to 1.5, I was not talked talking about the NuGet package (which is indeed 1.4), but about the RazorGenerator VS extension (Tools / Extensions & Updates).

Nov 28, 2012 at 4:59 PM

pranavkm:

Ah, interesting stuff, thanks. I do have the SVN extension installed so will disable that and see if it makes a difference. I’ll have a poke around in the cspjoj as well.

 I hope I can avoid having to workaround but thanks for your suggestion if it comes to that.

Nov 28, 2012 at 5:00 PM

davidebbo:

Thanks for clearing that up – yes, I do have v1.5 of the RazorGenerator VS extension so we can rule that out.

Nov 28, 2012 at 9:19 PM
Edited Nov 28, 2012 at 9:20 PM

Well I've found where the generated filename is persisted, so that clears up the second of my questions. There's this in the csproj file

    <Content Include="Views\Home\About.cshtml">
      <Generator>RazorGenerator</Generator>
      <LastGenOutput>About1.generated.cs</LastGenOutput>
    </Content>

- deleting the LastGenOutput element resets it and allows About.generated.cs to be created if the existing file is deleted and "Run Custom Tool" is clicked (or the view is saved).

 

I think I've found a reliable repo procedure, on my machine at least. I've tried many combinations of editing, saving, running the app, deleting generated files, removing the custom tool setting, editing the csproj etc. I also uninstalled the AnkhSVN extension that I'd been using. The process that repeatably produces these duplicate files is (and I know how unlikely this sounds):

  1. Set Custom Tool to "RazorGenerator"; observe the generated file being created.
  2. Run the application.
  3. Browse to the route corresponding to this view.
  4. Edit the view; observe the duplicate file being created.

I can't think of any justification for step 3, but without this step no duplicate is created. Editing another view (e.g. Contact.cshtml) resulted in no duplicate until I browsed to /Home/Contact and repeated the edit. Crazy!

Coordinator
Nov 28, 2012 at 9:31 PM

Strange, I just tried these steps and still can't repro. Couple things to try (independently, not in sequence):

  • after step 3, check if you can manually delete the generated file
  • go in App_Start\RazorGeneratorMvcStart.cs and set UsePhysicalViewsIfNewer to false, to see if that makes a difference
Coordinator
Nov 28, 2012 at 9:48 PM

For step 3, can you verify if doing this is causing the file to be locked by some process? Try using Process Explorer or something equivalent. Perhaps VS comes up with the alternate name if it is unable to write to the file.

Nov 29, 2012 at 11:22 AM

Sorry for the delay; work and sleep got in the way.

Observation (and a VS thing rather than a RazorGenerator thing I assume): the <LastGenOutput> element isn't removed in the csproj XML when I remove the custom tool setting from a view (which is why views can "remember" their incremented suffix even after I think I've removed all custom tool settings).

davidebbo:

  • i was able to delete both the original generated file and the one with the collision-avoiding suffix.
  • preliminary finding is that UsePhysicalViewsIfNewer = false *does* prevent the duplicate creation, but there's a side-effect. With this setting, editing and saving the .cshtml then refreshing the page in the browser doesn't show any changes. I expect that's because the physical view is being ignored and the compiled view is unchanged (the app hasn't restarted). I don't think you were suggesting this as a solution so I won't labour the point.

pranavkm:

  • using "Find" in Process Explorer returns no results for "About.generated.cs" (or indeed ".generated.cs").
Nov 29, 2012 at 11:46 AM
Edited Nov 29, 2012 at 12:51 PM

Just a thought, and probably something that's occurred to you, but it does make sense to me that VS would refuse to modify a .cs source file while an application is running. Maybe... somewhere... the message that "this file cannot be modified while the application is running" is being interpreted as "that file path can't be written to, so probably already exists, so I should create a non-colliding filename and try again".

To confuse matters, I had Edit And Continue enabled for most of this time, but disabling it didn't appear to have any effect on the file duplication.

Coordinator
Nov 29, 2012 at 7:18 PM

VS only prevents source files from being modified when you're debugging, and not when you're just running. Or maybe you were in fact debugging? If so, does plain running (Ctrl-F5) make a difference?

Also, if that were the reason, I don't see why changing UsePhysicalViewsIfNewer would make a difference.

Nov 30, 2012 at 6:54 AM

Yes, I'm pretty much always debugging if I'm running an application from VS. Sorry, I would have mentioned that if I'd thought it was unusual.

I tried running without debugging and no duplicate was produced. But then I tried running with debugging and no duplicate was produced. It's frustrating, but this morning I can't seem to repro at all. I have removed the UsePhysicalViewsIfNewer = false setting (and replaced with the original Request.IsLocal).

Coordinator
Nov 30, 2012 at 8:00 PM

Hmmm, it sounds like some kind of intermittent race condition. Those are always hard to track down!

Dec 3, 2012 at 8:15 AM

Ah, just my luck! I wonder what I've done to my dev machine to make it more prone to race conditions....

Thanks for your time on this problem; sounds like we've reached a bit of a dead end so I'll park this question and post back here if anything interesting turns up in the future.

Jon.