- Open a command prompt.
- Type msinfo32.
Thursday, August 21, 2014
Quick way to see system information
This gives you a bit more detail than System Properties.
Monday, August 4, 2014
Using layer diagrams to validate your architecture
A problem with solutions that have a more sophisticated architecture is ensuring that developers adhere to the design. It's pretty easy for a developer to inadvertently (or on purpose) ignore the system design and code it "just so it works". One of the tools you can use to combat this is using a layer diagram in Visual Studio 2013 to validate your architecture. This works best when adopting this from the very beginning of a project.
- Add a project using the Modeling Project template.
- From the Architecture menu, choose New Diagram.
- Choose Layer Diagram.
- You can drag "stuff" from both the Architecture Explorer as well as Solution Explorer.
- Each time you drag something to the diagram, you create a "layer" for that "artifact".
- I tend to group likewise classes into namespaces, so dragging namespaces from the Architecture Explorer works well for me.
- To create higher-level (project level) layers, instead of dragging the project into the diagram, it works better to create your own generic layer that is not tied to any code, and then dragging the namespace layers into your generic layers.
- You can also drag individual classes from Solution Explorer onto the diagram.
- Once you have all your layers defined, then select all of the layers, right click, and choose Generate Dependencies.
- At this point, if you right click in some white space and choose Validate Architecture, you should validate fine.
- If anyone goes rogue and violates your architecture, then Validate Architecture will fail and direct you to the offending code.
Extension Methods and Namespaces
When working with Extension Methods, they will not be available unless you import the namespace in which they are found. Extension methods appear that they are part of the object you are using but they are actually in a totally different module. So, they won't show up in intellisense or complile or that matter if you don't import the namespace.
Friday, August 1, 2014
Setting up a secure WCF web service from "scratch" with ASP.NET Identity
For this example, I'm using Visual Studio 2013 with Update 2 installed. Update 2 will ensure that the templates use the latest and greatest versions of all technologies involved.
Add a project using the WCF Service Application template. You could also use the Asp.Net Web Application template, but I think you'll just end up with a bunch of extra references you don't need. Now take a look at the web.config file. You'll notice that using this template automatically adds the protocolMapping element which allows the service to be accessed using https. If you did not use this template, you would have had to add this for https support. You'll also notice that there are no endpoints or bindings configured. That's because WCF has default bindings and IIS can determine the endpoint by examining the .svc file.
I delete the sample service created for you.
Next, I find it convenient to host the web services I'm developing on my local IIS. Click on My Project, Web tab, and type http://{name of your computer}.{domain}.{com}/{something meaningful}. It is important to use the fully qualified name of your computer because the certificate you will soon use is named the same and WCF won't like it if they are not the same. Click Create Virtual Directory. Open up IIS Manager, and change the app pool of the site to one with an associated identity of your (hopefully powerful) account. This becomes important when you connect to a database for authentication.
Add your web service by using the WCF Service template. Build the solution, and right click the service. Choose View in Browser to make sure all is well so far.
Now it's time to enable SSL (https). Read here to do this. At this point, you'll want to change the Project URL to include https on the Web tab when you go to My Project. I think it's a good idea to go ahead and setup a binding configuration and an endpoint. As I said earlier, WCF can figure all this out because of default values. However, Visual Studio's Add Service Reference automatic proxy generator can get confused when you are setting up a client. You can either use the Microsoft Service Configuration Editor (Right click web.config and choose Edit WCF Configuration) tool or edit the web.config by hand. If you use the tool, just click the Service folder, and choose Create a New Service. This will walk you through a wizard to create the service node. After that there is a link to create the binding configuration. You end up with this inside the <system.serviceModel> element:
You also need to set the multipleSiteBindingEnabled to False when you are using https:
At this point, I would create a little test app in a completely different solution and make sure you can call your new web service. A Windows Console app will work great. Just Add, Service Reference and specify the endpoint of the service. By adding the reference, Visual Studio will add the following to your app.config file:
There are a couple of things to note here. Why does the client configuration set up for basicHttpBinding when the server configuration is set up for basicHttpsBinding? Essentially basicHttpBinding and basicHttpsBinding are exactly the same. The only difference is that basicHttpsBinding includes the <security mode="Transport" /> by default.
Now that the web service is up and running with SSL we want to configure it to require credentials in order to access it. You can use the ASP.NET Membership, but this has been superceded by ASP.NET Identity and WCF doesn't directly interface with ASP.NET Identity yet. So, we will create a custom user name and password validator which we will eventually use to authenticate with ASP.NET Identity. First, we need to create the validator class itself. Add references to the following:
The only configuration change in your client console app is changing the security mode to "TransportWithMessageCredential". When you run your console, you will notice that you'll get an exception if you fail to provide credentials. To specify the client's credentials, do the following:
If the client provides accurate credentials, then the service will return results; otherwise, an exception will be thrown.
With this infrastructure in place, you can change the code in the CustomUserNameValidator class to connect to any database you want to authenticate. I mentioned earlier my desire to access ASP.NET Identity to authenticate users for the web service. In a separate solution, I have set up an ASP.NET MVC Web Application and configured it with ASP.NET Identity authentication. I am going to use this web application to administer user accounts for my web service. I simply add this class to my MVC project:
Now, if I can call this function from my CustomUserNameValidator in my WCF project, I will be authenticating using ASP.NET Identity. First add a reference to the dll produced by building the MVC project. Then, simply add this code to your CustomUserNameValidator:
Of course, it's not quite that easy. You need to do two more things:
So there we go. We now have a secure web service. Only accessible via https and secured by credentials stored in an ASP.NET Identity database.
Add a project using the WCF Service Application template. You could also use the Asp.Net Web Application template, but I think you'll just end up with a bunch of extra references you don't need. Now take a look at the web.config file. You'll notice that using this template automatically adds the protocolMapping element which allows the service to be accessed using https. If you did not use this template, you would have had to add this for https support. You'll also notice that there are no endpoints or bindings configured. That's because WCF has default bindings and IIS can determine the endpoint by examining the .svc file.
I delete the sample service created for you.
Next, I find it convenient to host the web services I'm developing on my local IIS. Click on My Project, Web tab, and type http://{name of your computer}.{domain}.{com}/{something meaningful}. It is important to use the fully qualified name of your computer because the certificate you will soon use is named the same and WCF won't like it if they are not the same. Click Create Virtual Directory. Open up IIS Manager, and change the app pool of the site to one with an associated identity of your (hopefully powerful) account. This becomes important when you connect to a database for authentication.
Add your web service by using the WCF Service template. Build the solution, and right click the service. Choose View in Browser to make sure all is well so far.
Now it's time to enable SSL (https). Read here to do this. At this point, you'll want to change the Project URL to include https on the Web tab when you go to My Project. I think it's a good idea to go ahead and setup a binding configuration and an endpoint. As I said earlier, WCF can figure all this out because of default values. However, Visual Studio's Add Service Reference automatic proxy generator can get confused when you are setting up a client. You can either use the Microsoft Service Configuration Editor (Right click web.config and choose Edit WCF Configuration) tool or edit the web.config by hand. If you use the tool, just click the Service folder, and choose Create a New Service. This will walk you through a wizard to create the service node. After that there is a link to create the binding configuration. You end up with this inside the <system.serviceModel> element:
<bindings> <basicHttpsBinding> <binding name="BasicHttpsBindingConfig" /> </basicHttpsBinding> </bindings> <services> <service name="AssemblyName.YourService"> <endpoint address="https://ComputerName.domain.whatever/IISSite/YourService.svc" binding="basicHttpsBinding" bindingConfiguration="BasicHttpsBindingConfig" contract="AssemblyName.IYourService" /> </service> </services>
You also need to set the multipleSiteBindingEnabled to False when you are using https:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" />
At this point, I would create a little test app in a completely different solution and make sure you can call your new web service. A Windows Console app will work great. Just Add, Service Reference and specify the endpoint of the service. By adding the reference, Visual Studio will add the following to your app.config file:
<bindings> <basicHttpBinding> <binding name="BasicHttpsBinding_IYourService"> <security mode="Transport" /> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="https://ComputerName.domain.whatever/IISSite/YourService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpsBinding_IYourService" contract="BenefitsServiceReference.IYourService" name="BasicHttpsBinding_IYourService" /> </client>
There are a couple of things to note here. Why does the client configuration set up for basicHttpBinding when the server configuration is set up for basicHttpsBinding? Essentially basicHttpBinding and basicHttpsBinding are exactly the same. The only difference is that basicHttpsBinding includes the <security mode="Transport" /> by default.
Now that the web service is up and running with SSL we want to configure it to require credentials in order to access it. You can use the ASP.NET Membership, but this has been superceded by ASP.NET Identity and WCF doesn't directly interface with ASP.NET Identity yet. So, we will create a custom user name and password validator which we will eventually use to authenticate with ASP.NET Identity. First, we need to create the validator class itself. Add references to the following:
- System.IdentityModel
- System.IdentityModel.Selectors
Imports System.IdentityModel.Selectors Imports System.ServiceModel Public Class CustomUserNameValidator Inherits UserNamePasswordValidator Public Overrides Sub Validate(userName As String, password As String) If Not (userName = "Steve" AndAlso password = "topsecret") Then Throw New FaultException("Unknown Username or Incorrect Password") End If End Sub End Class
It's pretty obvious what is happening here. If your User Name and Password is not right, an exception gets thrown back to the client. Now we have to configure the web service to use this. First of all we need to edit our binding configuration. Remember that by default basicHttpsBinding uses Transport as the Security mode. We need to change this to TransportWithMessageCredential. We are protecting (SSL) the service at the transport (IIS) level and authenticating at the message (web service) level. Here is the binding configuration after we do that:
<bindings> <basicHttpsBinding> <binding name="BasicHttpsBindingConfig"> <security mode="TransportWithMessageCredential" /> </binding> </basicHttpsBinding> </bindings>You also need to add a serviceCredentials behavior to your existing behavior element:
<behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="AssemblyName.CustomUserNameValidator, AssemblyName" /> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>As with most configuration changes, here you're definitely better off using the Service Configuration Editor tool. This is where we specify our custom class for validating the user name and password. Note the specific way that the class is specified along with the assembly that contains the class.
The only configuration change in your client console app is changing the security mode to "TransportWithMessageCredential". When you run your console, you will notice that you'll get an exception if you fail to provide credentials. To specify the client's credentials, do the following:
YourServiceProxy.ClientCredentials.UserName.UserName = "Steve" YourServiceProxy.ClientCredentials.UserName.Password = "topsecret"
If the client provides accurate credentials, then the service will return results; otherwise, an exception will be thrown.
With this infrastructure in place, you can change the code in the CustomUserNameValidator class to connect to any database you want to authenticate. I mentioned earlier my desire to access ASP.NET Identity to authenticate users for the web service. In a separate solution, I have set up an ASP.NET MVC Web Application and configured it with ASP.NET Identity authentication. I am going to use this web application to administer user accounts for my web service. I simply add this class to my MVC project:
Imports Microsoft.AspNet.Identity Imports Microsoft.AspNet.Identity.EntityFramework Public Module SecurityManager Public Function IsAuthenticated(userName As String, password As String) As Boolean Dim MyUserStore As UserStore(Of IdentityUser) = New UserStore(Of IdentityUser) Dim MyUserManager As UserManager(Of IdentityUser) = New UserManager(Of IdentityUser)(MyUserStore) Dim MyUser As IdentityUser = MyUserManager.Find(userName, password) If MyUser Is Nothing Then Return False Else Return True End If End Function End Module
Now, if I can call this function from my CustomUserNameValidator in my WCF project, I will be authenticating using ASP.NET Identity. First add a reference to the dll produced by building the MVC project. Then, simply add this code to your CustomUserNameValidator:
If Not SecurityManager.IsAuthenticated(userName, password) Then Throw New FaultException("Unknown Username or Incorrect Password") End If
Of course, it's not quite that easy. You need to do two more things:
- Use NuGet to install the same version of Entity Framework that your MVC project uses. This will setup your web.config with some special Entity Framework stuff that you will need.
- Copy the connectionStrings section out of the MVC web.config file and put it into the WCF web.config file. This connection string contains the database where the identity data is.
To get the name of the user who is accessing your service use this line:
System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity.Name
So there we go. We now have a secure web service. Only accessible via https and secured by credentials stored in an ASP.NET Identity database.
Subscribe to:
Posts (Atom)