Web application creation in IIS7 via MS.Web.Admin - iis-7

I am attempting to create seperate workflow instances as applications in IIS7 using the Microsoft.Web.Administration dll. When it attempts to add the Application to the Site ApplicationsCollection I get a COM error: "Invalid application path\r\n"
using (ServerManager manager = new ServerManager())
{
var site = manager.Sites.Where(x => x.Name == Properties.Settings.Default.WorkflowWebsiteName).Single();
StringBuilder stringBuilder = new StringBuilder()
.Append(m_workflowDefinition.AccountId)
.Append("/")
.Append(m_workflowDefinition.WorkflowDefinitionId)
.Append("/")
.Append(m_workflowDefinition.Version)
.Append("/");
string virtualPath = stringBuilder.ToString();
string physicalPath = Properties.Settings.Default.ApplicationPoolString +
virtualPath.Replace("/", "\\");
if (!Directory.Exists(physicalPath)) Directory.CreateDirectory(physicalPath);
//Create the workflow service definition file
using (StreamWriter writer = new StreamWriter(Path.Combine(physicalPath, m_workflowDefinition.WorkflowName + WORKFLOW_FILE_EXTENSION)))
{
writer.Write(m_workflowDefinition.Definition);
}
//Copy dependencies
string dependencyPath = m_workflowDefinition.DependenciesPath;
CopyAll(new DirectoryInfo(dependencyPath), new DirectoryInfo(physicalPath));
//Create a new IIS application for the workflow
var apps = site.Applications.Where(x => x.Path == virtualPath);
if (apps.Count() > 0)
{
site.Applications.Remove(apps.Single());
}
Application app = site.Applications.Add(virtualPath, physicalPath);
app.ApplicationPoolName = "Workflow AppPool";
app.EnabledProtocols = PROTOCOLS;
manager.CommitChanges();
}
The value assigned to virtualPath is like: "something/something/something" and for physicalPath it is "c:\inetpub\wwwroot\Workflow\something\something\something". Any ideas?
Any help is greatly appreciated.

Try changing your "something/something/something" path to "/something/something/something". The IIS administration call needs the extra slash at the beginning of the path.

Related

EPPLUS package works fine locally but returns Internal server error when deployed to azure server

I have my web api that uploads and reads an excel file from the client app and then afterwards saves the data into the database, the application works perfect on locally server but the problem comes when the application is deployed to azure server it returns error 500 internal server error therefore i don't understand why this happens and and don't know how i can track to understand what might be the cause below are my code blocks.
My Interface Class
public interface UploadExcelInterface
{
Task UploadMultipleClients(Client obj);
}
My Service Implementation
public class UploadExcelService : UploadExcelInterface
{
private readonly DbContext _connect;
private readonly IHttpContextAccessor httpContextAccessor;
public UploadExcelService(DbContext _connect, IHttpContextAccessor httpContextAccessor)
{
this._connect = _connect;
this.httpContextAccessor = httpContextAccessor;
}
public async Task UploadMultipleClients(Client obj)
{
var file = httpContextAccessor.HttpContext.Request.Form.Files[0];
if (file != null && file.Length > 0)
{
var folderName = Path.Combine("Datas", "ClientUPloads");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
var fileName = Guid.NewGuid() + ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fullPath = Path.Combine(pathToSave, fileName);
var clientsList = new List<Client>();
using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
FileInfo excelFile = new FileInfo(Path.Combine(pathToSave, fileName));
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (ExcelPackage package = new ExcelPackage(excelFile))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
var rowcount = worksheet.Dimension.Rows;
for (int row = 2; row <= rowcount; row++)
{
var Names = (worksheet.Cells[row,2].Value ?? string.Empty).ToString().Trim();
var Address = (worksheet.Cells[row,3].Value ?? string.Empty).ToString().Trim();
var Title = (worksheet.Cells[row,4].Value ?? string.Empty).ToString().Trim();
var Product = (worksheet.Cells[row,5].Value ?? string.Empty).ToString().Trim();
var Order = (worksheet.Cells[row,6].Value ?? string.Empty).ToString().Trim();
var Email = (worksheet.Cells[row,7].Value ?? string.Empty).ToString().Trim();
var Price = (worksheet.Cells[row,8].Value ?? string.Empty).ToString().Trim();
clientsList.Add(new Client
{
Names = Names,
Address = Address,
Title = Title,
Product = Product,
Order = Order,
Email = Email,
Price = Price,
}
}
//adding clients into the database
foreach (Client client in clientsList)
{
var exist = _connect.client.Any(x => x.Email == client.Email);
if (!exist)
{
await _connect.client.AddAsync(client);
}
}
await _connect.SaveChangesAsync();
}
}
}
My Controller Class
[HttpPost]
public async Task UploadMultipleClients([FromForm] Client obj)
{
await uploadExcelInterface.UploadMultipleClients(obj);
}
}
Please any help regarding this error that am getting from the server, and addition on that is it possible to get the data from the excel file without uploading it to server if yes how? because i tried adding the file to memory stream an reading it from memory but it appers not work, any suggestions thanks.
My answer may not help you solve the problem directly, but it can locate the error step by step. After we fix the error, we should be able to solve the problem in this thread.
Suggestions
Please make sure you have inclue EPPlus library in your deploy content.
Enabling ASP.NET Core stdout log (Windows Server)
Azure App Service - Configure Detailed Error Logging
Why
After tested, I am sure azure webapp can support EPPlus. For 500 error, as we don't have a more specific error message to refer to, we can't quickly locate the problem. Following the suggested method, you will surely see some useful information.
E.g:
The class library of EPPlus was not found.
Folders such as Datas are not created.
The database connection string, the test environment and the production environment may be different.
...

unable to validate data in Framework 4.6.1

Recently I upgraded a project from Framework 4.6 to 4.6.1. We started facing the following issue:
We combine all the css files to generate a common css file. During this process AjaxControlToolkit Calendar creates a WebResource.axd file. When we try to process this file then the decryption fails and Error is thrown stating : "unable to validate data".
Following code is used:
var queryString = WebResourcePath.Split(new[] { '?' })[1];
var stringBuilder = new StringBuilder();
var textWriter = new StringWriter(stringBuilder);
var context = new HttpContext(new SimpleWorkerRequest("/WebResource.axd", queryString, textWriter));
var urlEncodedData = context.Request.QueryString["d"];
var encryptedData = HttpServerUtility.UrlTokenDecode(urlEncodedData);
var machineKeySection = typeof(MachineKeySection);
var paramTypes = new Type[] { typeof(bool), typeof(byte[]), typeof(byte[]), typeof(int), typeof(int) };
var encryptOrDecryptData = machineKeySection.GetMethod("EncryptOrDecryptData", BindingFlags.Static | BindingFlags.NonPublic, null, paramTypes, null);
try
{
var decryptedData = (byte[])encryptOrDecryptData.Invoke(null, new object[] { false, encryptedData, null, 0, encryptedData.Length });
var decryptedContent = Encoding.UTF8.GetString(decryptedData).Substring(1);
var resourceParts = decryptedContent.Split('|');
Assembly = AssemblyCache.Load(resourceParts[0]);
ResourceName = resourceParts[1];
}
catch (Exception ex)
{
throw ex;
}
Error is thrown on the line : var decryptedData = (byte[])encryptOrDecry........
Some solution I went through suggested use of static machine key but we are already doing it.
NOTE : This is occuring only when we set httpRuntime targetFramework to 4.6.1 otherwise it works as expected.
From forums.asp.net:
So our problem was that some Webresource.axd requests are cached by
browsers (we didn't knew that...) but our machinekeys changes.
Fix the machineKeys in Web.config and wait for all our users to clean
their browser cache.
Comment:
https://forums.asp.net/post/5620791.aspx
Full thread:
https://forums.asp.net/t/1963234.aspx?Unable+to+validate+data+EncryptOrDecryptData+problem
Hope that helps

Exchange Web Services bind Mailbox folder using FolderID and reflection

I am trying to load the Exchange Web Services DLL at runtime and connect to a mailbox. I am following this guide: Using Reflection to load unreferenced assemblies at runtime in C#
The code so far:
var DLL = Assembly.LoadFile(#"Microsoft.Exchange.WebServices.dll");
var theType = DLL.GetType("Microsoft.Exchange.WebServices.Data.ExchangeService");
var c = Activator.CreateInstance(theType);
var method = theType.GetMethod("AutodiscoverUrl");
method.Invoke(c, new object[] { #"anyvalid#email.com" });
After that code I am lost. How do I use the ExchangeService to bind a Mailbox object using a FolderId? EWS Managed API is not an option for my server and application.
This is the Powershell script equivalent code that I am trying to implement in ASP.NET:
$MailboxName = "account#domain"
$dllpath = "Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.AutodiscoverUrl("anyvalid#email.com")
$mbfolderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)
$MsgRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$mbfolderid)
Using reflection is tedious. You are on the right track though. The following code shows how you can bind to the "Inbox" folder and get the subjects of the first 10 email messages.
Notice how I use the dynamickeyword so I do not have to call MethodInfo.Invoke to call instance methods on the reflected types.
string mailboxName = "...";
// Get value for enum WellKnownFolderName.Inbox.
var wellKnownFolderNameType = assem.GetType("Microsoft.Exchange.WebServices.Data.WellKnownFolderName");
var rootFolderName = wellKnownFolderNameType
.GetField("Inbox")
.GetValue(null)
;
// Create requested mailbox and folderid for Inbox-folder for the requested mailbox.
var mailboxType = assem.GetType("Microsoft.Exchange.WebServices.Data.Mailbox");
dynamic mailbox = Activator.CreateInstance(mailboxType, new object[] { mailboxName });
var folderIdType = assem.GetType("Microsoft.Exchange.WebServices.Data.FolderId");
dynamic folderId = Activator.CreateInstance(folderIdType, rootFolderName, mailbox);
// Bind to the Inbox-folder for the requested mailbox.
var folderType = assem.GetType("Microsoft.Exchange.WebServices.Data.Folder");
var bindMethod = folderType.GetMethod("Bind", new Type[] { serviceType, folderIdType });
dynamic folder = bindMethod.Invoke(null, new object[] { service, folderId });
// Get 10 first mailitems
var itemViewType = assem.GetType("Microsoft.Exchange.WebServices.Data.ItemView");
dynamic itemView = Activator.CreateInstance(itemViewType, 10);
dynamic findItemsResults = folder.FindItems(itemView);
foreach (dynamic item in findItemsResults.Items)
{
Console.WriteLine((string) item.Subject);
}

How to create an exe for a web application?

I had developed a web application using Visual studio 2012 (ASP.Net 4.5 - C#) and a web service. Both are laying in a single solution. I need to convert my solution to an EXE file (Creating EXE for my web application). What i need exactly is, if run my setup file, it should host my web application and web service in IIS. Kindly provide the steps to solve me the problem.
Quiet a late answer:
I cannot post the whole project here but i'll post the flow chart here and you may try it.
All the steps in the flowchart here should be controlled programmatically.
1. Steps in starting the application.
NOTE: Please ignore the third layer (Is website added) if you are using a local database(.mdf)
The connection string to be used for a local database:
public string ConnectionString =
"Data Source=(local);Initial Catalog=YOUR_DATABASE_NAME;Integrated Security=True";
But still remember that you need dotnet framework to be installed inorder to run your application. don't worry as you can set the pre-requisites in your application setup project.
All the codes for the flowchart process below.
Is IIS Installed:
NOTE: I am posting the code for IIS 7 and above.
public bool IsIISInstalled()
{
return Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp",
"VersionString", null) != null;
}
Install IIS
public int InstallIIS()
{
string DISM_CMD_CODE = "START /WAIT DISM /Online /Enable-Feature /FeatureName:IIS-ApplicationDevelopment /FeatureName:IIS-ASP /FeatureName:IIS-ASPNET /FeatureName:IIS-BasicAuthentication /FeatureName:IIS-CGI /FeatureName:IIS-ClientCertificateMappingAuthentication /FeatureName:IIS-CommonHttpFeatures /FeatureName:IIS-CustomLogging /FeatureName:IIS-DefaultDocument /FeatureName:IIS-DigestAuthentication /FeatureName:IIS-DirectoryBrowsing /FeatureName:IIS-FTPExtensibility /FeatureName:IIS-FTPServer /FeatureName:IIS-FTPSvc /FeatureName:IIS-HealthAndDiagnostics /FeatureName:IIS-HostableWebCore /FeatureName:IIS-HttpCompressionDynamic /FeatureName:IIS-HttpCompressionStatic /FeatureName:IIS-HttpErrors /FeatureName:IIS-HttpLogging /FeatureName:IIS-HttpRedirect /FeatureName:IIS-HttpTracing /FeatureName:IIS-IIS6ManagementCompatibility /FeatureName:IIS-IISCertificateMappingAuthentication /FeatureName:IIS-IPSecurity /FeatureName:IIS-ISAPIExtensions /FeatureName:IIS-ISAPIFilter /FeatureName:IIS-LegacyScripts /FeatureName:IIS-LegacySnapIn /FeatureName:IIS-LoggingLibraries /FeatureName:IIS-ManagementConsole /FeatureName:IIS-ManagementScriptingTools /FeatureName:IIS-ManagementService /FeatureName:IIS-Metabase /FeatureName:IIS-NetFxExtensibility /FeatureName:IIS-ODBCLogging /FeatureName:IIS-Performance /FeatureName:IIS-RequestFiltering /FeatureName:IIS-RequestMonitor /FeatureName:IIS-Security /FeatureName:IIS-ServerSideIncludes /FeatureName:IIS-StaticContent /FeatureName:IIS-URLAuthorization /FeatureName:IIS-WebDAV /FeatureName:IIS-WebServer /FeatureName:IIS-WebServerManagementTools /FeatureName:IIS-WebServerRole /FeatureName:IIS-WindowsAuthentication /FeatureName:IIS-WMICompatibility /FeatureName:WAS-ConfigurationAPI /FeatureName:WAS-NetFxEnvironment /FeatureName:WAS-ProcessModel /FeatureName:WAS-WindowsActivationService";
string command = DISM_CMD_CODE;
ProcessStartInfo pStartInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
Process p = new Process();
p.StartInfo = pStartInfo;
//p.WaitForExit();
p.Start();
return 1;
}
Is Website added
public bool IsWebsiteAddedInIIS(string WebsiteName)
{
ServerManager serverManager = new ServerManager();
var site = serverManager.Sites.FirstOrDefault(s => s.Name == WebsiteName);
if (site == null)
{
//No site added
return false;
}
else
{
//site added
return true;
}
}
public int CreateNewWebsite(string SiteName, string PublishedFilesPath)
{
ServerManager serverManager = new ServerManager();
var site = serverManager.Sites.FirstOrDefault(s => s.Name == SiteName);
if (site == null)
{
serverManager.Sites.Add(SiteName, "http", "*:8080:", PublishedFilesPath);
serverManager.CommitChanges();
return 1;
}
else
{
return 2;
}
}
public void StartWebsite(string SiteName)
{
ServerManager serverManager = new ServerManager();
var site = serverManager.Sites.FirstOrDefault(s => s.Name == SiteName);
if (site != null)
{
site.Stop();
site.Start();
}
}
public void StopWebsite(string SiteName)
{
ServerManager serverManager = new ServerManager();
var site = serverManager.Sites.FirstOrDefault(s => s.Name == SiteName);
if (site != null)
{
site.Stop();
}
}
Get website URL
public string GetWebsiteURL(string SiteName)
{
//string SiteUrl = "";
//ServerManager serverManager = new ServerManager();
//var site = serverManager.Sites.FirstOrDefault(s => s.Name == SiteName);
//var siteBindings = site.GetCollection("bindings");
//string protocol = (string)siteBindings["protocol"];
//string bindingInfo = (string)siteBindings["bindingInformation"];
//if (protocol.StartsWith("http", StringComparison.OrdinalIgnoreCase))
//{
// string[] parts = bindingInfo.Split(':');
// if (parts.Length == 3)
// {
// //Get the port in use HERE !!!
// string port = parts[1];
// SiteUrl = "localhost:" + port;
// }
//}
//return SiteUrl;
int port = 0;
string SiteUrl = "";
ServerManager serverManager = new ServerManager();
var site = serverManager.Sites.FirstOrDefault(s => s.Name == SiteName);
foreach (Binding binding in site.Bindings)
{
port = binding.EndPoint.Port;
SiteUrl = "localhost:" + port + "/index.aspx";
break;
}
return SiteUrl;
}
Init Browsing the website
You have to install Cefsharp chromium browser to your windows forms
Install-Package CefSharp.WinForms -Version 75.1.143
public void InitBrowser(string Address)
{
Cef.Initialize(new CefSettings());
browser = new ChromiumWebBrowser(Address);
Controls.Add(browser);
browser.Dock = DockStyle.Fill;
}
Thank you..
Maybe you need to create a web setup project. "A Web setup project provides the
highest level of flexibility for deploying a website. Although Web Setup Projects are more
complex for the developer, they allow you to generate an MSI package, precompile a website,
and perform virtually any setup task that your application might require.
Many websites do not require custom configuration. In these cases, you can simply build
your MSI file and be ready to deploy. However, more complex scenarios include dependencies
(such as particular operating system versions or service packs), custom registry entries,
or administrator configuration. Web Setup Projects allow you to deploy websites that meet
these requirements."
Check the book "MCTS Self-Paced Training Kit (Exam 70-515) - Web Applications Development with Microsoft .NET Framework 4" at the chapter 8 "Debugging and deploying".
Hope this helps.

System.DirectoryServices - The server is not operational

I get an error by a website, on which I use Windows Authentication.
Strange things:
Only occurs if user is not yet saved into database (new unknown user)
Appears only on live system, everything fine on local development environment
This is what I get in a logging mail:
Source : System.DirectoryServices
Message: The server is not operational.
Trace:
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
at Smarthouse.Labs.DataAccess.UserListManager.SaveUser(String windowsUserName)
This is how I implement DirectorySearch:
private void SaveUser(string windowsUserName)
{
string[] domainAndUser = windowsUserName.Split('\\');
string domain = domainAndUser[0];
string username = domainAndUser[1];
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher search = new DirectorySearcher(entry);
try
{
// Bind to the native AdsObject to force authentication.
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("sn");
search.PropertiesToLoad.Add("givenName");
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();
if (result == null)
{
throw new Exception("No results found in Windows authentication.");
}
User userToSave = new User();
userToSave.FirstName = (String) result.Properties["givenName"][0];
userToSave.LastName = (String) result.Properties["sn"][0];
userToSave.Email = (String) result.Properties["mail"][0];
userToSave.Username = windowsUserName;
userToSave.Guid = Guid.NewGuid();
SaveUser(userToSave);
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message, ex);
}
finally
{
//Dispose service and search to prevent leek in memory
entry.Dispose();
search.Dispose();
}
}
If more code examples are needed just tell me.
Your problem is that you're using a "plain" domain name to bind - this won't work in LDAP. Actually, if you try to bind to LDAP://MyDomain, what you're really doing is trying to bind to the server called MyDomain.
You need a valid LDAP bind string - something like LDAP://dc=yourdomain,dc=local or something.
To find out what your default LDAP binding context is, use this code snippet:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://RootDSE");
if (deRoot != null)
{
string defaultNamingContext = deRoot.Properties["defaultNamingContext"].Value.ToString();
}
Once you have that string - use that as your bind string to your LDAP server.
And if you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context -- no domain name needed, uses default domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if(user != null)
{
// do something here....
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
You can use bind strings in the format LDAP://mydomain.com:389. I kept getting "Access is Denied" when trying to use the format LDAP://DC=mydomain,DC=com. Once I switched to the LDAP://mydomain.com:389 format, and bound using the AuthenticationTypes.ServerBind flag when constructing my DirectoryEntry, it worked great. This was in Azure App Service.
To add to marc_s's answer above, I needed to search multiple domains.
So for each Domain I did the following:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://" +"DomainName"+ "/RootDSE");
string defaultNamingContext = "LDAP://" + deRoot.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry mySearchRoot = new DirectoryEntry(defaultNamingContext);
DirectorySearcher myDirectorySearcher = new DirectorySearcher(mySearchRoot);
Similar Error Happened to me (though it happened all the time and not in specific cases like pointed out here) because of a wrong Active Directory connection string. i used the corp instead the prod one .
Use something that works for another app in your organization if exists.

Resources