How to include custom web.config files as part of package? - sharepoint-2010

I'm a newbie at SharePoint 2010. I right-click on the project, select Deploy if I want to deploy locally. The Site URL on the project is set to my local machine. If I want to deploy to the QA server, I select Deploy, navigate to the Debug/Release folder, grab the .wsp file, logon to the Central Administration on QA, retract the solution, then do Add-SPsolution <path to wsp file> through powershell, go back to Central Admin, the click on Deploy solution for that package. Works fine.
The web.config on my local machine has a custom connection string, and appsettings. When I deploy the package on the QA server, I'm manually changing the connection string and appsettings specific to QA. I want to automate this process. I want the web.config to be part of the package with it's own custom connecting string (one for local, one for QA, and for Production) and appsettings. How do I do it? The goal is on a new machine, I should be able to deploy the wsp and appsettings+web.config should all be correct without modifying anything manually. How do I accomplish this?

I am pretty sure web.config modifications can't be done with just package files / CAML.
However, what can be done is to deploy a WebApplication Feature Reciever which modifies the web.config through SPWebApplication.WebConfigModifications.
Here is a snippet of code from my project, see the the Code Project KB for more details: (This first bit is just a handy function with some notes.)
// For WebConfigModifications access,
// see http://www.codeproject.com/KB/sharepoint/SPWebConfigModTool.aspx
// Hints:
// app.WebConfigModifications.Add(new SPWebConfigModification
// {
// Type = [add/update child node?]
// Path = [XPath of parent node]
// Name = [XPath to identify child node UNIQUELY]
// Owner = [Use GUID to identify as ours]
// Sequence = [Sequence number, likely 0 for only one]
// Value = [XML node to add/update]
// });
void ModfiyWebConfig (SPWebApplication app, string path, string name, XElement node)
{
app.WebConfigModifications.Add(new SPWebConfigModification
{
Type = SPWebConfigModificationType.EnsureChildNode,
Path = path,
Name = name,
Owner = OwnerId,
Sequence = 0,
Value = node.ToString(),
});
}
Get/init SPWebApplication
var app = properties.Feature.Parent as SPWebApplication;
Queue/setup modifications
ModfiyWebConfig(app,
"configuration/system.webServer/modules",
"add[#name='ASPxHttpHandlerModule']",
new XElement("add",
new XAttribute("name", "ASPxHttpHandlerModule"),
new XAttribute("type", aspxHandlerModule)));
Apply modifications
app.WebService.ApplyWebConfigModifications();
app.Update();

Related

Spring Cloud Server serving multiple property files for the same application

Lets say I have applicationA that has 3 property files:
-> applicationA
- datasource.properties
- security.properties
- jms.properties
How do I move all properties to a spring cloud config server and keep them separate?
As of today I have configured the config server that will only read ONE property file as this seems to be the standard way. This file the config server picks up seems to be resolved by using the spring.application.name. In my case it will only read ONE file with this name:
-> applicationA.properties
How can I add the other files to be resolved by the config server?
Not possible in the way how you requested. Spring Cloud Config Server uses NativeEnvironmentRepository which is:
Simple implementation of {#link EnvironmentRepository} that uses a SpringApplication and configuration files located through the normal protocols. The resulting Environment is composed of property sources located using the application name as the config file stem (spring.config.name) and the environment name as a Spring profile.
See: https://github.com/spring-cloud/spring-cloud-config/blob/master/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/NativeEnvironmentRepository.java
So basically every time when client request properties from Config Server it creates ConfigurableApplicationContext using SpringApplicationBuilder. And it is launched with next configuration property:
String config = application;
if (!config.startsWith("application")) {
config = "application," + config;
}
list.add("--spring.config.name=" + config);
So possible names for property files will be only application.properties(or .yml) and config client application name that is requesting configuration - in your case applicationA.properties.
But you can "cheat".
In config server configuration you can add such property
spring:
cloud:
config:
server:
git:
search-paths: '{application}, {application}/your-subdirectory'
In this case Config Server will search for same property file names but in few directories and you can use subdirectories to keep your properties separate.
So with configuration above you will be able to load configuration from:
applicationA/application.properies
applicationA/your-subdirectory/application.properies
This can be done.
You need to create your own EnvironmentRepository, which loads your property files.
org.springframework.cloud.config.server.support.AbstractScmAccessor#getSearchLocations
searches for the property files to load :
for (String prof : profiles) {
for (String app : apps) {
String value = location;
if (app != null) {
value = value.replace("{application}", app);
}
if (prof != null) {
value = value.replace("{profile}", prof);
}
if (label != null) {
value = value.replace("{label}", label);
}
if (!value.endsWith("/")) {
value = value + "/";
}
output.addAll(matchingDirectories(dir, value));
}
}
There you could add custom code, that reads the required property files.
The above code matches exactly the behaviour described in the spring docs.
The NativeEnvironmentRepository does NOT access GIT/SCM in any way, so you should use
JGitEnvironmentRepository as base for your own implementation.
As #nmyk pointed out, NativeEnvironmentRepository boots a mini app in order to collect the properties by providing it with - sort of speak - "hardcoded" {appname}.* and application.* supported property file names. (#Stefan Isele - prefabware.com JGitEnvironmentRepository ends up using NativeEnvironmentRepository as well, for that matter).
I have issued a pull request for spring-cloud-config-server 1.4.x, that supports defining additional file names, through a spring.cloud.config.server.searchNames environment property, in the same sense one can do for a single springboot app, as defined in the Externalized Configuration.Application Property Files section of the documentation, using the spring.config.name enviroment property. I hope they review it soon, since it seems many have asked about this feature in stack overflow, and surely many many more search for it and read the currently advised solutions.
It worths mentioning that many ppl advise "abusing" the profile feature to achieve this, which is a bad practice, in my humble opinion, as I describe in this answer

Application name is not set. Call Builder#setApplicationName. error

Application: Connecting to BigQuery using BigQuery APIs for Java
Environment: Eclipse, Windows 7
My application was running fine until last night. I've made no changes (except for restarting my computer) and my code is suddenly giving me this error:
Application name is not set. Call Builder#setApplicationName.
Thankfully I had a tar'd version of my workspace from last night. I ran a folder compare and found the local_db.bin file was different. I deleted the existing local_db.bin file and tried to run the program again. And it worked fine!
Any idea why this might have happened?
Hopefully this will help anyone else who stumbles upon this issue.
Try this to set your application name
Drive service = new Drive.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential)
.setApplicationName("Your app name")
.build();
If you are working with only Firebase Dynamic Links without Android or iOS app
Try this.
builder.setApplicationName(firebaseUtil.getApplicationName());
FirebaseUtil is custom class add keys and application name to this class
FirebaseDynamicLinks.Builder builder = new FirebaseDynamicLinks.Builder(
GoogleNetHttpTransport.newTrustedTransport(), JacksonFactory.getDefaultInstance(), null);
// initialize with api key
FirebaseDynamicLinksRequestInitializer firebaseDynamicLinksRequestInitializer = new FirebaseDynamicLinksRequestInitializer(
firebaseUtil.getFirebaseApiKey());
builder.setFirebaseDynamicLinksRequestInitializer(firebaseDynamicLinksRequestInitializer);
builder.setApplicationName(firebaseUtil.getApplicationName());
// build dynamic links
FirebaseDynamicLinks firebasedynamiclinks = builder.build();
// create Firebase Dynamic Links request
CreateShortDynamicLinkRequest createShortLinkRequest = new CreateShortDynamicLinkRequest();
createShortLinkRequest.setLongDynamicLink(firebaseUtil.getFirebaseUrlPrefix() + "?link=" + urlToShorten);
Suffix suffix = new Suffix();
suffix.setOption(firebaseUtil.getShortSuffixOption());
createShortLinkRequest.setSuffix(suffix);
// request short url
FirebaseDynamicLinks.ShortLinks.Create request = firebasedynamiclinks.shortLinks()
.create(createShortLinkRequest);
CreateShortDynamicLinkResponse createShortDynamicLinkResponse = request.execute();

Featurereceiver sharepoint 2010 xdocument 503

My issue seems to be related to permissions, but I am not sure how to solve it.
In the FeatureActivated event of one of my features I am calling out to a class I created for managing webconfig entries using the SPWebConfigModification class. The class reads up an xml file that I have added to the mapped Layouts folder in the project.
When I deploy the .wsp to my Sharepoint server everything gets installed fine, but when the FeatureActivated event runs it throws a 503 error when attempting to access the xml file.I am deploying the .wsp remotely using a powershell script and I have the powershell, the iisapp pool and the owstimer.exe all using the same domain administrative user.
I assumed the issue was that the FeatureActivated event code was being run within the scope of the OWSTIMER.exe so changed the logon of the service to a domain user that has administrative access to the server to see if that would solve the problem, but no matter what I am getting the 503.
I have traced out the URL to the xml file and pasted that into IE and I am getting back the xml without issue from the server once its copied.
Can anyone give me any idea where to look to figure out why the FeatureActivated event code can't seem to get to the XML file on the server?
Below is the code in my class that is being called from the FeatureActivated event to read the xml.
_contentservice = ContentService;
WriteTraceMessage("Getting SPFeatureProperties", TraceSeverity.Medium, 5);
_siteurl = properties.Definition.Properties["SiteUrl"].Value;
_foldername = properties.Definition.Properties["FolderName"].Value;
_filename = properties.Definition.Properties["FileName"].Value;
_sitepath = properties.Definition.Properties["SitePath"].Value;
WriteTraceMessage("Loading xml from layouts for configuration keys", TraceSeverity.Medium, 6);
xdoc = new XDocument();
XmlUrlResolver resolver = new XmlUrlResolver();
XmlReaderSettings settings = new XmlReaderSettings();
StringBuilder sb = new StringBuilder();
sb.Append(_siteurl).Append("_layouts").Append("/").Append(_foldername).Append("/").Append(_filename);
WriteTraceMessage("Path to XML: " + sb.ToString(), TraceSeverity.Medium, 7);
WriteTraceMessage("Credentials for xml reader: " + CredentialCache.DefaultCredentials.ToString(), TraceSeverity.Medium, 8);
resolver.Credentials = CredentialCache.DefaultCredentials; //this the issue might be here
settings.XmlResolver = resolver;
xdoc = XDocument.Load(XmlReader.Create(sb.ToString(), settings));
I finally punted on this issue because I discovered that while adding the -Force switch to the Enable-SPFeature command did use a different process to activate the feature when adding a solution it did not work when updating a solution. Ultimately I just changed my XDocument.Load() to use a TextReader instead of a URI. The xml file will always be available when deploying the WSP because it is part of the package so there is no reason to use IIS and a webrequest to load up the xml.

How to link a PDF Document to a Record using Visual Studio LightSwitch 2011?

I'm Stuck the following problem: How can I link a PDF Document to a Record in a Data Grid using Visual Studio LightSwitch 2011 and Visual Basic?
Any help would be awesome, thanks!
Here's the simplest way to do this: add a custom command to the Command Bar of the Data Grid Row for your Data Grid. In this example I'm calling the command Open PDF File. Then add this code to Execute code for the command:
partial void OpenPDFFile_Execute()
{
const string LOCAL_SERVER_PDF_DIR = #"\\MyServer\PDFs\";
const string WEB_SERVER_PDF_DIR = "http://myweb.server/PDFs/";
const string PDF_SUFFIX = ".pdf"; //assumes you do not include the extension in the db field value
if (AutomationFactory.IsAvailable)
{
//if the AutomationFactory is available, this is a desktop deployment
//use the shell to open a PDF file from the local network
dynamic shell = AutomationFactory.CreateObject("Shell.Application");
string filePath = LOCAL_SERVER_PDF_DIR + this.PDFFiles.SelectedItem.FileName + PDF_SUFFIX;
shell.ShellExecute(filePath);
}
else
{
//otherwise this must be a web deployment
//in order to make this work you must add a reference to System.Windows.Browser
//to the Client project of your LS solution
var uri = new Uri(WEB_SERVER_PDF_DIR + this.PDFFiles.SelectedItem.FileName + PDF_SUFFIX);
HtmlPage.Window.Navigate(uri, "_blank");
}
}
You will need to add the following imports to the top of your user code file to make this code compile:
using System.Runtime.InteropServices.Automation;
using System.Windows.Browser;
I should mention that you need a directory to server the PDFs up from. This example is flexible with respect to deployment, because it handles both desktop and web configurations. Since you'll need to set up the PDF directoy, you may want to just handle one configuration option to simply things (or you could expose the same PDF directory over http and as a local network share).
You may also want to present this as a true link instead of a button. In order to do this, you'll need a custom SilverLight control. In any case, I would recommend implementing the PDF link using a button first. You can then move this same code to a link event handler as a separate project if that is worth spending time on.

Challenges with Associating files

In my project properties I go to publish, options, and file associations and enter ".cms", "Contact manager File" "pqcms" and "1icon.ico", but when I publish and install it does not appear to associate the files...I want to be able to double click on the file and have it open the program but it does not appear to do so.
I believe there are ways to edit the registry if you run your program as an administrator, but I really need clickonce to be happy with me because I am maximizing the features. Isn't clickonce supposed to set up the file association for me? Why isn't it?
and final question: what can I do without elevating privileges to administrator?
Have you added the code required to handle the user double-clicking on the file?
//Get the ActivationArguments from the SetupInformation property of the domain.
string[] activationData =
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
if (activationData != null)
{
Uri uri = new Uri(activationData[0]);
string fileNamePassedIn = uri.LocalPath.ToString();
//now you have the file name and you can handle it
}
One other thing to beware of. I originally converted this code (provided by RobinDotNet) to vb.net. Now I've converted the project to c# and ran into something interesting. When debugging (and I'd imagine if you chose to have the exe accessible as opposed to the click once reference app) "AppDomain.CurrentDomain.SetupInformation.ActivationArguments" is null (no activation arguments were assigned) so I modified the code slightly to trap this error.
//Get the ActivationArguments from the SetupInformation property of the domain if any are set.
if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments != null)
{
string[] activationData =
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
if (activationData != null)
{
Uri uri = new Uri(activationData[0]);
string fileNamePassedIn = uri.LocalPath.ToString();
//now you have the file name and you can handle it
}
}