One of the things I really hate about 2010 and the packaging solution that comes out-of-the box is that it encourages bad practices (plopping everything - web code, static artifacts, packaging) into one project.
There are lots of issues with this, but the most egregious issue -- in my opinion -- is that it forces the creation of artifacts in a hierarchy that needs to map to the SharePoint deployment targets instead of making sense in the logical structure of the application and code. I find that this decreases navigability and if some code is separated out into other libraries, just makes things that much harder to find and find a home for.
With 2007 and even with 2010, when using WSPBuilder, I've followed the standard project layout pattern of having at least three projects:
- Package - The package project that encapsulates the deployment artifacts and the deployment artifacts ONLY
- Web - The UI project that contains the static web artifacts, the ASPX pages, the ASMX endpoints, the WCF endpoints, etc. - has no direct reference to SharePoint
- Core - A class library project with the core business logic - encapsulates the direct reference to SharePoint. Feature receivers, event receivers, base classes, domain model classes, data mapping classes, helper classes, etc. go here.
With WSPBuilder, it was easy to separate the artifacts by simply using XCOPY on pre- or post-build to move artifacts from the Web project to the Package project before calling the WSPBuilder executable. WSPBuilder didn't care if the .aspx or .js or .css file was part of the VS solution tree; it would include it in the package if it was in the directory on the file system.
This allowed me to separate web code from the SharePoint code and build a nice boundary to prevent "leakage" of SharePoint API calls to the web artifacts (as well as logically organize the web code into a hierarchy that made more sense). In other words, it forced everything on the front-end in Web to call through a domain model in Core. The Web project becomes a "pure" ASP.NET web application that has no knowledge of SharePoint. I can have strong ASP.NET developers work on the front-end and strong SharePoint developers work on the domain model without giving the ASP.NET guys a chance to "cheat" and write "dirty" code in the codebehind since they have no reference to SharePoint.
I've been trying to figure out how exactly this type of separation can be duplicated with the OOB packaging with Visual Studio 2010.
The core problem with VS2010 is that the contents of mapped folders (i.e. Layouts) don't get included in the manifest and package if they are not included in the project in the VS solution. In other words, if I just XCOPY the files from the Web project to the Package project, they don't get added to the package because -- even though they are in the file system -- they are not part of the solution.
One workaround is to manually create "stubs" for the files (same name) in mapped Layouts directory so that when the XCOPY occurs, it's copying the latest file and replacing the placeholder in the package. But this seems a pain in the butt, redundant, and easy for developers to forget when adding new files.
But I'm curious how other shops out there are handling this issue. I feel strongly that for any non-prototype code, this type of separation becomes a must to ensure maintainability and approachability of the code for new developers. Are there workarounds to short-circuit the OOB packaging quirks that can be automated and remove manual steps like creating a stub .aspx? Are there alternative patterns for separating logic out of the package?
BeforeLayout
target is not enough as it does the copy fine and the file ends up in the package, but the file is not added to the manifest. As far I can tell, the manifest is not generated as a part of the msbuild process so there is no way to control how it's generated aside from the basic manifest merge as it doesn't seem like new files are picked up automatically and added to the manifest dynamically. Wondering if there are more sophisticated ways to manipulate the manifest now.