Here's sample code:
private static Raven.Client.Embedded.EmbeddableDocumentStore _documentStore;
public static Raven.Client.Embedded.EmbeddableDocumentStore documentStore
{
get
{
if (_documentStore == null)
{
_documentStore = new Raven.Client.Embedded.EmbeddableDocumentStore
{
DataDirectory = "App_Data/RavenDbData",
UseEmbeddedHttpServer = true
};
_documentStore.Initialize();
}
return _documentStore;
}
}
The exception message looke like this when the _documentStore.Initialize(); line is called:
System.Net.HttpListenerException: The process cannot access the file because it is being used by another process
It turns out that this exception gets thrown if port 8080 is used by anything else. The fix was to add this bit to the web.config to change the port number (pick any port number)
<appSettings>
<add key="Raven/Port" value="8082"/>
</appSettings>
Related
I'm teaching myself Blazor and have run into this conundrum, where I get this error:
{"No connection could be made because the target machine actively refused it."}
The uri I call is this one:
api/employee
However, when use the full uri, such as this:
https://localhost:44376/api/employee
I get no errors at all.
Even though this is just a practice project, I'd still prefer to use a relative uri without a port number, but am not sure how to make it work.
Here's the method where I am making these calls:
public async Task<IEnumerable<Employee>> GetAllEmployees()
{
bool isEmployeeListEmpty = true; ;
IEnumerable<Employee> employeeList = null;
try
{
//string uriEmployeeList = $"https://localhost:44376/api/employee";
string uriEmployeeList = $"api/employee";
var employees = await JsonSerializer.DeserializeAsync<IEnumerable<Employee>>
(await _httpClient.GetStreamAsync(uriEmployeeList), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
if (employees != null)
{
isEmployeeListEmpty = false;
employeeList = await JsonSerializer.DeserializeAsync<IEnumerable<Employee>>
(await _httpClient.GetStreamAsync(uriEmployeeList), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
else
{
isEmployeeListEmpty = true;
}
}
catch (Exception ex)
{
Console.WriteLine("An exception occurred inside the GetAllEmployees() method of the EmployeeDataService class");
Console.WriteLine(ex.Message);
}
if (!isEmployeeListEmpty)
return employeeList;
else
return null;
}
I am doing this all on one machine with IIS Express.
UPDATE
Thank you all for your help and suggestions. It turned out that I had the ssl port defined as 44376 in the lauchSettings.json, while I had the base addresses in Startup.cs file set as https://localhost:44340/ for all three HttpClient objects I use. I changed the port in each of the base addresses to 44376 to match the 44376 port I have set up in the launchSettings.json file, and everything now works with the relative/abbreviated uri strings.
Please see if api and web project are set under "Multiple startup" and both are ACTION : "start" are not (Right click on Solution > Set Startup Projects), its seems like api project is not started and refuse the connection and getting similar error while accessing the api controller.
I'm using Fileless Activation, here is my full web.config on the server side, which has two endpoints:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</configSections>
<connectionStrings>
<add name="RedStripe"
connectionString="Data Source=S964;Initial Catalog=MyDatabase;Persist Security Info=True;User ID=sa;Password=***;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.web>
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment>
<!-- where virtual .svc files are defined -->
<serviceActivations>
<add service="Company.Project.Business.Services.AccountClassService"
relativeAddress="Account/AccountClassService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="Account/AccountService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
Here is my CustomServiceHostFactory:
public class CustomServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new CustomServiceHost(serviceType, baseAddresses);
}
}
And here is my CustomServiceHost:
public class CustomServiceHost : ServiceHost
{
public CustomServiceHost(Type serviceType, Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void InitializeRuntime()
{
AddServiceDebugBehavior();
AddWcfMessageLoggingBehavior();
AddGlobalErrorHandlingBehavior();
AddServiceCredentialBehavior();
AddEndpoints();
ConfigureThrottling();
base.InitializeRuntime();
}
private void AddEndpoints()
{
var wsHttpBinding = WcfHelpers.ConfigureWsHttpBinding();
foreach (Uri address in BaseAddresses)
{
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding, new EndpointAddress(address));
AddServiceEndpoint(endpoint);
//adding mex
AddServiceMetadataBehavior();
AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
address.AbsoluteUri + "/mex");
break;
}
}
private void AddGlobalErrorHandlingBehavior()
{
var errorHanlderBehavior = Description.Behaviors.Find<GlobalErrorBehaviorAttribute>();
if (errorHanlderBehavior == null)
{
Description.Behaviors.Add(new GlobalErrorBehaviorAttribute(typeof(GlobalErrorHandler)));
}
}
private void AddServiceCredentialBehavior()
{
var credentialBehavior = Description.Behaviors.Find<ServiceCredentials>();
if (credentialBehavior == null)
{
var customAuthenticationBehavior = new ServiceCredentials();
customAuthenticationBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
customAuthenticationBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNamePasswordValidator();
Description.Behaviors.Add(customAuthenticationBehavior);
}
}
private void AddServiceDebugBehavior()
{
var debugBehavior = Description.Behaviors.Find<ServiceDebugBehavior>();
if (debugBehavior == null)
{
Description.Behaviors.Add(
new ServiceDebugBehavior() {IncludeExceptionDetailInFaults = true});
}
else
{
if (!debugBehavior.IncludeExceptionDetailInFaults)
debugBehavior.IncludeExceptionDetailInFaults = true;
}
}
private void AddServiceMetadataBehavior()
{
var metadataBehavior = Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
serviceMetadataBehavior.HttpsGetEnabled = true;
Description.Behaviors.Add(serviceMetadataBehavior);
}
}
private void AddWcfMessageLoggingBehavior()
{
var messageInspectorBehavior = Description.Behaviors.Find<WcfMessageInspector>();
if (messageInspectorBehavior == null)
{
Description.Behaviors.Add(new WcfMessageInspector());
}
}
private void ConfigureThrottling()
{
var throttleBehavior = Description.Behaviors.Find<ServiceThrottlingBehavior>();
if (throttleBehavior != null) return;
throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 100,
MaxConcurrentInstances = 100,
MaxConcurrentSessions = 100
};
Description.Behaviors.Add(throttleBehavior);
}
}
Finally here is the WcfHelper where the binding is defined. This is in a shared location so I can programmatically configure the client side binding using the same:
public class WcfHelpers
{
public static WSHttpBinding ConfigureWsHttpBinding()
{
return new WSHttpBinding
{
Name = "myWSHttpBinding",
OpenTimeout = new TimeSpan(0, 10, 0),
CloseTimeout = new TimeSpan(0, 10, 0),
SendTimeout = new TimeSpan(0, 10, 0),
MaxBufferPoolSize = 104857600,
MaxReceivedMessageSize = 104857600,
Namespace = Constants.RedStripeNamespace,
ReaderQuotas = new XmlDictionaryReaderQuotas()
{
MaxDepth = 104857600,
MaxStringContentLength = 104857600,
MaxArrayLength = 104857600,
MaxBytesPerRead = 104857600,
MaxNameTableCharCount = 104857600
},
Security =
{
Mode = SecurityMode.TransportWithMessageCredential,
Message = { ClientCredentialType = MessageCredentialType.UserName }
}
};
}
}
When I publish this WebHost project and try to browse to one of the two addreses like so:
https://myserver/Project/Account/AccountService.svc
I get the following error:
The provided URI scheme 'http' is invalid; expected 'https'. Parameter
name: context.ListenUriBaseAddress
I notice that in the CustomServiceHost AddEndpoints() method, when looping over BaseAddresses, if I hardcode an address there like so:
https://myserver/Project/Account/AccountService.svc
I can then browse to it successfully. How do the BaseAddresses get built when using fileless activation and relative addressing? Where can I specify they use https (where it seems they are using http now)?
Thanks in advance.
Edit 1: This will fix the problem but seems like a total hack, where do I specify https using fileless activation so the relative address builds with https?
var endpoint = new ServiceEndpoint(ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding, new EndpointAddress(address.OriginalString.Replace("http:", "https:")));
Edit 2: I think I'm gaining an understanding of what is going on here. Thank you #Andreas K for pointing me in the right direction. If I go into IIS and look at the bindings for the site, there are multiple as indicated by the image:
I put some code to write to a database inside my AddEndpoints() method when looping over BaseAddresses. When I try to use the browser to get to the service like so: https://my.server.local/Project/Account/AccountService.svc, TWO entries are created in the database.
http://my.server.local/Project/Account/AccountService.svc
https://my.server.local/Project/Account/AccountService.svc
Thus, it seems the IIS SITE BINDING is being picked up. However, now I'm not sure why there aren't more entries in the database for the BaseAddresses. Where are the net.pipe, net.tcp, etc?
It turns out the BaseAddresses come from the IIS binding as mentioned in my Update 2, and again thanks to #Andreas K for pointing me to the right direction. In IIS I have one website with multiple applications under it. I have both http and https enabled on those bindings. I have updated my AddEndpoings() method in the CustomServiceHost to look like this:
private void AddEndpoints()
{
var wsHttpBinding = WcfHelpers.ConfigureWsHttpBinding();
foreach (var address in BaseAddresses.Where(a => a.Scheme == Uri.UriSchemeHttps))
{
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding,
new EndpointAddress(address));
AddServiceEndpoint(endpoint);
AddServiceMetadataBehavior();
}
}
Since other applications under the site need http, my BaseAddresses always contains two (http and https). I needed to manually filter the http ones since I don't want to expose them for this particular site. Now that I know HOW they are being populated I am satisfied. Thanks all.
Try this:
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; // no password
// If you are not using IIS, you need to bind cert to port
Process proc = new Process();
proc.StartInfo.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), "netsh.exe");
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.Arguments =
string.Format("http add sslcert ipport={0}:{1} certhash={2} appid={{{3}}}", ip, port, cert.Thumbprint, Guid.NewGuid());
proc.Start();
proc.WaitForExit();
To get a cert do the following (note cert must be in cert store):
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
cert = store.Certificates.Find(X509FindType.FindBySubjectName, certSubject, false)[0];
This will work without IIS. If you are using IIS you don't need to bind cert to port (I think)
I found this on the msdn:
File-less Activation
Although .svc files make it easy to expose WCF services, an even easier approach would be to define virtual activation endpoints within Web.config, thereby removing the need for .svc files altogether.
In WCF 4, you can define virtual service activation endpoints that map to your service types in Web.config. This makes it possible to activate WCF services without having to maintain physical .svc files (a.k.a. “file-less activation”). The following example shows how to configure an activation endpoint:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="Greeting.svc" service="GreetingService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
With this in place, it’s now possible to activate the GreetingService using a relative path of “Greeting.svc” (relative to the base address of the Web application). In order to illustrate this, I’ve created an IIS application on my machine called “GreetingSite”, which I assigned to the “ASP.NET v4.0” application pool, and mapped it to the GreetingService project directory that contains the web.config shown above. Now I can simply browse to http://localhost/GreetingSite/Greeting.svc without actually having a physical .svc file on disk. Figure 9 shows what this looks like in the browser.
I hope this can help you
I have defined my Custom Error pages in my global.asax.cs and can get them working locally in IIS Express with VS 2013, but when I publish to the server running IIS 7 the 401 and 403 errors do not display the custom error page but rather return a 500 and not the custom 500 page either. I've tried many solutions found here on SO but none have worked. Anyone have any thoughts?
Web.Config portions:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error">
</customErrors>
</system.web>
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
Global.asax portions:
protected void Application_Error()
{
string descriptor = null;
string errMsg = null;
string additionalInfo = null;
string title = null;
Exception lastError = null;
Exception ex = null;
if (HttpContext.Current.Server.GetLastError() != null)
{
ex = HttpContext.Current.Server.GetLastError().GetBaseException();
if (ex.GetType() == typeof (HttpException))
{
HttpException httpException = (HttpException) ex;
switch (httpException.GetHttpCode())
{
case 404:
title = "Not Found";
descriptor = "Page Not Found";
errMsg =
"The page you requested could not be found, either contact your webmaster or try again. Use your browsers Back button to navigate to the page you have prevously come from.";
additionalInfo =
"We are working hard to correct this issue. Please wait a few moments and try your search again.";
lastError = new Exception(errMsg);
break;
case 500:
title = "Server Error";
descriptor = "Oooops, Something went wrong!";
errMsg = "You have experienced a technical error. We apologize.";
additionalInfo =
"We are working hard to correct this issue. Please wait a few moments and try your search again.";
lastError = new Exception(errMsg);
break;
}
CallErrorController(descriptor, additionalInfo, title, lastError, httpException.GetHttpCode());
}
}
}
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode == 401 || Response.StatusCode == 403)
{
Response.ClearContent();
string additionalInfo = null;
string title = null;
const string errMsg =
#"You have attempted to access a resource for which you do not have the proper authorization or which is not available from your location.
If you received this message by clicking on a link on this website, please report it to the webmaster. Use your browsers Back
button to navigate to the page you have previously come from.";
const string descriptor = "Access is Denied";
title = descriptor;
Exception lastError = new Exception(errMsg);
CallErrorController(descriptor, additionalInfo, title, lastError, Response.StatusCode);
}
}
private void CallErrorController(string descriptor, string additionalInfo, string title, Exception lastError, int statusCode)
{
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
HttpContextWrapper contextWrapper = new HttpContextWrapper(this.Context);
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Index");
routeData.Values.Add("statusCode", statusCode);
routeData.Values.Add("exception", lastError);
routeData.Values.Add("descriptor", descriptor);
routeData.Values.Add("additionalInfo", additionalInfo);
routeData.Values.Add("title", title);
routeData.Values.Add("isAjaxRequet", contextWrapper.Request.IsAjaxRequest());
IController controller = new ErrorController();
RequestContext requestContext = new RequestContext(contextWrapper, routeData);
controller.Execute(requestContext);
Response.End();
}
ErrorController:
public class ErrorController : Controller
{
public ActionResult Index(int statusCode, Exception exception, string descriptor, string additionalInfo, string title, bool isAjaxRequet)
{
if (!isAjaxRequet)
{
ErrorModel model = new ErrorModel { HttpStatusCode = statusCode, Exception = exception, Descriptor = descriptor, AdditionalInfo = additionalInfo, Title = title};
return View("Error", model);
}
else
{
// Otherwise, if it was an AJAX request, return an anon type with the message from the exception
var errorObjet = new { message = exception.Message };
return Json(errorObjet, JsonRequestBehavior.AllowGet);
}
}
}
Running Locally:
Running From the Server:
Try adding this to your web.config
<configuration>
... //all the other gubbins that goes in your web config
<system.webServer>
<httpErrors errorMode="Detailed" />
</system.webServer>
</configuration>
Or turning on detailed errors via the iis adamin module
My application changes end-point settings at run-time and persists the changes to config file. But when I create a new service proxy instance, the end-point settings are the ones that were before the update. How do I force the proxy to get new settings?
You will need to detect if your configuration file has been updated be it your main app.config / web.config or any external configuration file you are using via configSource.
If a change is detected you will need to refresh the system.serviceModel configuration section:
ConfigurationManager.RefreshSection("system.serviceModel/client");
Existing Channels and ChannelFactories will not pick up the changes so they will need to be closed and new ones created.
The following example shows this in action:
[TestFixture]
class When_trying_to_change_service_endpoints_on_the_fly
{
[Test]
public void Should_use_the_new_endpoint()
{
var someService1 = Substitute.For<ISomeWebService>();
var someService2 = Substitute.For<ISomeWebService>();
var serviceHost1 = CreateServiceHost(someService1, new Uri("http://localhost:50001"));
var serviceHost2 = CreateServiceHost(someService2, new Uri("http://localhost:50002"));
serviceHost1.Open();
serviceHost2.Open();
UpdateEndpointInConfig(new Uri("http://localhost:50001"));
var channelFactory = new ChannelFactory<ISomeWebService>("TestReloadConfig");
var channel1 = channelFactory.CreateChannel();
channel1.ServiceMethod();
((IChannel)channel1).Close();
channelFactory.Close();
UpdateEndpointInConfig(new Uri("http://localhost:50002"));
channelFactory = new ChannelFactory<ISomeWebService>("TestReloadConfig");
var channel2 = channelFactory.CreateChannel();
channel2.ServiceMethod();
((IChannel)channel2).Close();
serviceHost1.Close();
serviceHost2.Close();
someService1.Received(1).ServiceMethod();
someService2.Received(1).ServiceMethod();
}
private static void UpdateEndpointInConfig(Uri endpointAddress)
{
var configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
var config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
var serviceModelConfig = (ServiceModelSectionGroup) config.GetSectionGroup("system.serviceModel");
serviceModelConfig.Client.Endpoints[0].Address = endpointAddress;
config.Save();
ConfigurationManager.RefreshSection("system.serviceModel/client");
}
private ServiceHost CreateServiceHost<TService>(TService service, Uri baseUri)
{
var serviceHost = new ServiceHost(service, new Uri[0]);
serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
serviceHost.AddServiceEndpoint(typeof(TService), new BasicHttpBinding(), baseUri);
return serviceHost;
}
}
[ServiceContract]
public interface ISomeWebService
{
[OperationContract]
void ServiceMethod();
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:50000" binding="basicHttpBinding" contract="Junk.ISomeWebService" name="TestReloadConfig" />
</client>
</system.serviceModel>
</configuration>
If you managed the endpoint configurations another way you could update any ChannelFactory instance manually as you have access to the Endpoint and Binding properties.
var store = new DocumentStore()
{
Url = #"http://localhost"
};
store.Initialize();
Blog blog = new Blog()
{
Title = "Hello RavenDB",
Category = "RavenDB",
Content = "This is a blog about RavenDB",
Comments = new BlogComment[]{
new BlogComment() { Title = "Unrealistic", Content= "This example is unrealistic"},
new BlogComment() { Title = "Nice", Content= "This example is nice"}
}
};
using (IDocumentSession session = store.OpenSession())
{
session.Store(blog);
session.SaveChanges();
}
The above code saves data to the default database. (It is a web application.) But I want it save data to another database that I created the raven management studio (web page). Where do i specify the database name? Also please tell me how I can save the connection string with the database name in the config file. This is how I would save it to config file without the database name
<connectionStrings>
<add name="Local" connectionString="DataDir = ~\Data"/>
<add name="Server" connectionString="Url = http://localhost:8080"/>
</connectionStrings>
All of your questions are explained in the documentation:
new DocumentStore
{
ConnectionStringName = "Local"
}
<connectionStrings>
<add name="Local" connectionString="DataDir=~\Data;Database=MyDatabaseName"/>
<add name="Server" connectionString="Url=http://localhost:8080;Database=MyDatabaseName"/>
</connectionStrings>
The other answers are ok, but for efficiency you really only want one instance of DocumentStore for your application, unless you are running multiple Raven servers and then it would be acceptable to have one per server.
If you are just connecting to different databases on the same server, you should use:
var store = new DocumentStore(...your connection string or inline options...);
using (var session = store.OpenSession("the database name")
{
...
}
You can keep your connection strings data as you shown, best with the databases names at the end:
<connectionStrings>
<add name="Core" connectionString="Url=http://localhost:8082/databases/Core"
providerName="My primary database." />
<add name="Backup" connectionString="Url=http://localhost:8082/databases/Backup"
providerName="My backup stuff." />
</connectionStrings>
Next you can implement singleton class which will keep all your handlers for defined sources, for example:
public class DocumentStoreProvider : IDocumentStoreProvider
{
private static readonly IDictionary<string, IDocumentStore> _documentStores = new Dictionary<string, IDocumentStore>();
private static readonly DocumentStoreProvider _instance = new DocumentStoreProvider();
private DocumentStoreProvider()
{
var connectionStrings = ConfigurationManager.ConnectionStrings;
foreach (ConnectionStringSettings connectionString in connectionStrings)
{
var name = connectionString.Name;
var connection = connectionString.ConnectionString;
IDocumentStore currentStore = new DocumentStore { ConnectionStringName = name };
currentStore.Initialize();
currentStore.DatabaseCommands.EnsureDatabaseExists(name);
IndexCreation.CreateIndexes(Assembly.Load("Your.Assembly.Containing.Indexes"), currentStore);
_documentStores.Add(name, currentStore);
}
}
public static DocumentStoreProvider Instance
{
get { return _instance; }
}
public IDocumentStore GetDocumentStore(string key)
{
return _documentStores[key];
}
}
The usage can be following:
using (var session = DocumentStoreProvider.Instance.GetDocumentStore("Backup").OpenSession())
{
/* do stuff for chosen database... */
session.Store(something);
session.SaveChanges();
}