How to programmatically save a copy of a Microsoft Project Online project? - project-server

I need to save local copies of all my projects stored in my PWA instance at Microsoft Project Online frequently. I have hundreds of them so doing it manually is not an option.
I've been able to connect to the PWA instance with Project Server CSOM and .NET and read the data. But I couldn't find a way within the Microsoft.ProjectServer.Client namespace to export this data and save it locally to any MS Project-readable file.
Is this even possible at all?
Alternatively, any other way to achieve this not involving the Project Server CSOM would be welcome.
Edit: I've also tried to obtain the data through the Project Online REST API, so I can get a XML file that I could use as if it were a MSPDI file. But neither MS Project Professional (the desktop application) nor MPXJ library recognize it, I might need to do some heavy transformation and that doesn't guarantee it will even work...

In the end I decided to go the "ugly but working" way, directly telling MS Project desktop client to connect, open and locally save the project, with some C# code:
private static void start()
{
var objProcess = Process.Start(#"winproj.exe", "/s https://PWA-URL");
}
static void Main(string[] args)
{
var backgroundThread = new Thread(new ThreadStart(start));
backgroundThread.Start();
Thread.Sleep(10000);
ApplicationClass objProject = new ApplicationClass
{
Visible = false
};
object oMissing = System.Reflection.Missing.Value;
object oFile = #"<>\test-project";
object oFormat = "MSProject.mpp";
object oReadOnly = true;
objProject.DisplayAlerts = false;
objProject.FileOpen(oFile, oReadOnly, PjMergeType.pjDoNotMerge, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oFormat, oMissing, PjPoolOpen.pjPoolReadOnly, oMissing, oMissing, oMissing, oMissing);
objProject.FileSaveAs(#"C:\Windows\Temp\LocalCopy.mpp");
objProject.Quit(PjSaveType.pjDoNotSave);
}
Windows Credentials are used to connect to the PWA, although different user and password could specified but I haven't tried (ApplicationClass.FileOpen).
One should also import Microsoft.Office.Interop.MSProject.dll to compile the project.

Related

Hosting a web server in a local enviroment using only Flutter

Is it possible to host a Flutter web app on a local environment using a Flutter desktop-based app?
The google-search for a solution like this can be difficult, since it involves many keywords that lead to similar situations (online hosting when you need a local solution, command-line only solution, and so on).
After some digging, I ended up using the shelf package to deploy my own Flutter web app on a local network. I developed this for Windows only, so I can't guarantee it will work on other platforms.
First thing to do is obviously adding the shelf package in your pubspec.yaml: after that, this is how my main method looks like
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf_router/shelf_router.dart' as shelf_router;
[...]
void main() async{
[...]
var secureContext = SecurityContext();
try {
//privKey and cert are the String names of the two files for the SSL connection,
//placed in the root directory of the flutter project or along with the .exe file (when released)
secureContext.usePrivateKey(privKey);
secureContext.useCertificateChain(cert);
} catch (error) {
logger.e("Error on init SecurityContext");
}
try {
//this is the handler that deploys the files contained in 'webAppFolder': I just simply pasted the result of
//the flutter webapp building inside (the index.html file is the default one for flutter web)
//and put the folder in the root of the flutter project (or, again, in the same folder with the .exe file when released)
final _staticHandler = createStaticHandler("webAppFolder", defaultDocument: 'index.html');
//this I kept just for a reminder on how to deploy a static page, if needed
final _router = shelf_router.Router()
..get(
'/time',
(request) => shelf.Response.ok(DateTime.now().toUtc().toIso8601String()),
);
final cascade = shelf.Cascade()
.add(_staticHandler)
.add(_router);
try {
var server = await shelf_io.serve(
cascade.handler,
InternetAddress.anyIPv4,
mainPort, //this is the number of the port on which the webapp is deployed (I load this from a .ini file beforehand
securityContext: secureContext,
);
// Enable content compression
server.autoCompress = true;
logger.i("Serving at https://${server.address.host}:${server.port}");
} catch (err) {
logger.e("Error while serving");
logger.e(err.toString());
}
} catch (err) {
logger.e("Error while creating handler");
logger.e(err.toString());
}
runApp(MaterialApp(
[...]
This is the part related to the deploy of a web app: since the flutter desktop app already provides a GUI, I used that to add some maintenance and testing utilities to check if everything is working fine.
For more details regarding shelf, refer to their API on their pub.dev page.

Does build pipeline requires internate connection to run

I am using Onprimise AzureDevOps. I am having intranet within the server but no access to internet.
Does the Use Nugget and Nugget installer requires internet to get it success.
If you look here you will find this code:
async function getLatestMatchVersionInfo(versionSpec: string): Promise<INuGetVersionInfo> {
taskLib.debug('Querying versions list');
let versionsUrl = 'https://dist.nuget.org/tools.json';
let proxyRequestOptions = {
proxy: taskLib.getHttpProxyConfiguration(versionsUrl)
};
let rest: restm.RestClient = new restm.RestClient('vsts-tasks/NuGetToolInstaller', undefined, undefined, proxyRequestOptions);
let nugetVersions: INuGetVersionInfo[] = (await rest.get<INuGetVersionInfo[]>(versionsUrl, GetRestClientOptions())).result;
// x.stage is the string representation of the enum, NuGetReleaseStage.Value = number, NuGetReleaseStage[NuGetReleaseStage.Value] = string, NuGetReleaseStage[x.stage] = number
let releasedVersions: INuGetVersionInfo[] = nugetVersions.filter(x => x.stage.toString() !== NuGetReleaseStage[NuGetReleaseStage.EarlyAccessPreview]);
let versionStringsFromDist: string[] = releasedVersions.map(x => x.version);
let version: string = toolLib.evaluateVersions(versionStringsFromDist, versionSpec);
if (!version)
{
taskLib.error(taskLib.loc("Error_NoVersionWasFoundWhichMatches", versionSpec));
taskLib.error(taskLib.loc("Info_AvailableVersions", releasedVersions.map(x => x.version).join("; ")));
throw new Error(taskLib.loc("Error_NuGetToolInstallerFailer", NUGET_TOOL_NAME));
}
return releasedVersions.find(x => x.version === version);
}
And it basically looks for nuget version if it will not find it on local machine. I assume that all this REST calls will not work without internet. So if you do not want to provide access to internet you should use only those versions installed on agents.
Agree with Krzysztof Madej, I think it is feasible to run build pipeline without internet connection. From the description of NuGet tool installer task we can know :
Acquires a specific version of NuGet from the internet or the tools
cache and adds it to the PATH.
So you need to make sure that the nuget version you need is installed on the local machine.
If you don't use upstream packages from the feed in your DevOps server, then your DevOps server machine could just in intranet network.
However, your build agent machine requires internet access, if you to do something that requires to access internet, such as Use Nuget task.

EventLog Production

I have a console application that is responsible for saving a record in the Windows Event Viewer, but it does not work on a clean machine, despite having already installed the .Net Framework.
Create an installer which is responsible for creating the route HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\MyLogEvent
When running the installed application, it does the whole process without throwing any errors, but it is not saving anything in the Event Viewer.
A strongname has already been added.
string origen = "ErrorGeneric";
EventLogEntryType severidad = EventLogEntryType.Error
if (!EventLog.SourceExists(origen))
{
EventLog.CreateEventSource(origen, "MyLogEvent");
while (!EventLog.SourceExists(origen))
{
Console.Write(".");
Thread.Sleep(1000);
}
}
EventLog log = new EventLog() { Source = origen };
log.WriteEntry(logString.ToString(), severidad);
I found the error, I needed to add the source to the installation, so that it was created in the windows registry

How to automate the verify, repair and upgrade activity in ALM QC upgrade

I am currently taking care of ALM QC upgrade activity from 11 to 12.20.
During this i need to verify, repair and upgrade each project.
Is there any way to automate this?
I am open on using UFT or selenium.
Let me know if there is any other way to do this.
I'd recommend using SaApi. You can read more about it in
ALM help-> API references -> HP ALM Site Administration API Reference
Basically it's a dll that is a COM object, so you can register it by regsvr32 and use it in your .NET application or vbs application.
To get this dll just login to site admin once - and you'll have it along with other site admin libraries in a path like this ->
C:\Users\YOUR_USERNAME\AppData\Local\HP\ALM-Client\YOUR_ALM_NAME
run cmd.exe as Administrator
register SAClient.dll in cmd
-> C:\Windows\system32>regsvr32 C:\Users\YOUR_USERNAME\AppData\Local\HP\ALM-Client\YOUR_ALM_NAME\SAClient.dll
Now you can add SAClient to your project references.
Create a simple client.
public class ALMSiteAdminClient
{
private SAapi sconnection = new SAapi();
public void connect(string url, string user, string password)
{
sconnection.Login(url, user, password);
}
public void disconnect()
{
sconnection.Logout();
}
public void verifyProject(string domain, string project)
{
sconnection.Verify(domain, project, "basic");
}
public void repairProject(string domain, string project)
{
sconnection.Repair(domain, project, "");
}
public void upgradeProject(string domain, string project)
{
sconnection.Upgrade(domain, project, "");
}}
Use the client ;)
static void Main(string[] args)
{
//get list of a projects from anywhere you want
//this is just a mock example
Dictionary<string, string> projects = new Dictionary<string, string>();
projects.Add("domain1", "project1");
projects.Add("domain1", "project2");
//create site admin client and login
ALMSiteAdminClient SACLIENT = new ALMSiteAdminClient();
SACLIENT.connect("http://myd-vm15059.hpeswlab.net:8081/qcbin", "sa","");
//do whatever you need with each project
foreach (KeyValuePair<string, string> project in projects)
{
SACLIENT.verifyProject(project.Key, project.Value);
SACLIENT.repairProject(project.Key, project.Value);
SACLIENT.upgradeProject(project.Key, project.Value);
}
//logout
SACLIENT.disconnect();
}}
I ended up using HP ALM Robot for auto upgrading QC projects. At the time there wasnt much documentation apart from: https://community.softwaregrp.com/dcvta86296/attachments/dcvta86296/itrc-895/91467/1/Robot_User_Guide_0.pdf
Now there are videos to help out the process too: https://www.youtube.com/watch?v=l-McyxeW0aI

Has anyone successfully deployed a GWT app on Heroku?

Heroku recently began supporting Java apps. Looking through the docs, it seems to resemble the Java Servlet Standard. Does anyone know of an instance where a GWT app has been successfully deployed on Heroku? If so, are there any limitations?
Yes, I've got a successful deployment using the getting started with Java instructions here:
http://devcenter.heroku.com/articles/java
I use the Maven project with appassembler plugin approach but added gwt-maven-plugin to compile a GWT app during the build.
When you push to heroku you see the GWT compile process running, on one thread only so quite slow but it works fine.
The embedded Jetty instance is configured to serve up static resources at /static from src/main/resources/static and I copy the compiled GWT app to this location during the build and then reference the .nocache.js as normal.
What else do you want to know?
You've got a choice, either build the Javascript representation of your GWT app locally into your Maven project, commit it and the read it from your app, or to generate it inside Heroku via the gwt-maven-plugin as I mentioned.
The code to serve up files from a static location inside your jar via embedded Jetty is something like this inside a Guice ServletModule:
(See my other answer below for a simpler and less Guice-driven way to do this.)
protected void configureServlets() {
bind(DefaultServlet.class).in(Singleton.class);
Map<String, String> initParams = new HashMap<String, String>();
initParams.put("pathInfoOnly", "true");
initParams.put("resourceBase", staticResourceBase());
serve("/static/*").with(DefaultServlet.class, initParams);
}
private String staticResourceBase() {
try {
return WebServletModule.class.getResource("/static").toURI().toString();
}
catch (URISyntaxException e) {
e.printStackTrace();
return "couldn't resolve real path to static/";
}
}
There's a few other tricks to getting embedded Jetty working with guice-servlet, let me know if this isn't enough.
My first answer to this turned out to have problems when GWT tried to read its serialization policy. In the end I went for a simpler approach that was less Guice-based. I had to step through the Jetty code to understand why setBaseResource() was the way to go - it's not immediately obvious from the Javadoc.
Here's my server class - the one with the main() method that you point Heroku at via your app-assembler plugin as per the Heroku docs.
public class MyServer {
public static void main(String[] args) throws Exception {
if (args.length > 0) {
new MyServer().start(Integer.valueOf(args[0]));
}
else {
new MyServer().start(Integer.valueOf(System.getenv("PORT")));
}
}
public void start(int port) throws Exception {
Server server = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setBaseResource(createResourceForStatics());
context.setContextPath("/");
context.addEventListener(new AppConfig());
context.addFilter(GuiceFilter.class, "/*", null);
context.addServlet(DefaultServlet.class, "/");
server.setHandler(context);
server.start();
server.join();
}
private Resource createResourceForStatics() throws MalformedURLException, IOException {
String staticDir = getClass().getClassLoader().getResource("static/").toExternalForm();
Resource staticResource = Resource.newResource(staticDir);
return staticResource;
}
}
AppConfig.java is a GuiceServletContextListener.
You then put your static resources under src/main/resources/static/.
In theory, one should be able to run GWT using the embedded versions of Jetty or Tomcat, and bootstrap the server in main as described in the Heroku Java docs.