I have a service,
[ServiceContract]
public interface IProduct
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/Products/Update")]
void Update(Product product);
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/Products")]
Product[] Get();
}
Now I only want a specific user in domain to be able to update products and call this method, only way I can thing of is in method itself check if logged in user is the user I want to give permissions, Is there any better way ?
Update(Product product)
{
if (HttpContext.Current.User.Identity.Name == "Something")
{
// update product
}
}
Well , you can use PriciplePermission attribute to allow specific users/groups access to specific resources. Internally ASP.Net Role provider is utilized.This attribute can be used at class level as well as on individual method(s).
For implementation details -
https://msdn.microsoft.com/en-us/library/ms731200(v=vs.110).aspx
Related
I am using a wcf web service as the persistence layer for a backbone.js application.
[OperationContract]
[WebGet]
public IEnumerable<AnalysisParameterSet> AnalysisParameters()
{
// implementation
}
[OperationContract]
[WebInvoke(Method = "POST")]
public void AnalysisParameters(IEnumerable<AnalysisParameterSet> parameterSets)
{
// implementation
}
I would like to create two methods on the service with the same name, but different signatures, one for GET and one for POST.
However wcf is complaining that there are 2 methods with the same name. I am aware I could use the name property of the OperationContract to differentiate them. This is not ideal as backbone prefers for the methods to share the same name.
Can i use the same method name for both GET and POST?
If I can't do this in WCF. How would I modifiy backbone.js to use a different method for post and Get.
I believe what you want is something like:
[OperationContract]
[WebGet(UriTemplate = "/AnalysisParameters")]
public IEnumerable<AnalysisParameterSet> GetAnalysisParameters()
{
// implementation
}
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/AnalysisParameters")]
public void PostAnalysisParameters(IEnumerable<AnalysisParameterSet> parameterSets)
{
// implementation
}
Depending on the http method (post/get), one or the other function will be called.
I am looking for something like the AuthorizeAttribute in MVC, something I can use like this:
[WebGet(UriTemplate = "data/{spageNumber}")]
[WebCache(CacheProfileName = "SampleProfile")]
[WcfAuthorize]
public IEnumerable<SampleItem> GetCollection(String spageNumber)
{
Int32 itemsPerPage = 10;
Int32 pageNumber = Int32.Parse(spageNumber);
return Enumerable.Range(pageNumber * itemsPerPage, itemsPerPage)
.Select(i => SampleItem.Create(i));
}
That WcfAuthorizeAttribute, will try to authenticate the user with FormsAuthentication, and set the context's IPrincipal, or return a HTTP 401 Unauthorized.
I have tried with a IOperationBehavior, but I gets executed in the first method, whichever it be, not in the method I have set the attribute.
How can this be achieved in WCF REST?
Regards.
PS: I have seen the RequestInterceptor example in the Starter Kit, but what I want is put it in some methods only, and the example looks like a filter you execute in all the operations.
You can use AOP to achieve this. I have used PostSharp as an AOP tool to achieve this functionality. You can also find a sample on their website. The OnMethodEntry gets executed before a method (that is decorated with this attribute) is executed and you can perform your validation there.
I did a quick sample to test this and it worked.
[Serializable]
[ProvideAspectRole(StandardRoles.Security)]
public class WcfAuthorizeAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
//extract forms authentication token here from the request and perform validation.
}
}
And you could decorate your WCF methods like below.
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1
{
[WcfAuthorize]
[WebGet(UriTemplate = "")]
public List<SampleItem> GetCollection()
{
return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } };
}
My service interface is:
[ServiceContract]
public interface IMyService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "HelloJSON/{name}")]
string HelloJSON(string name);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "GetEmployees")]
List<Employee> GetEmployees();
}
My implementation is:
public class MyService : IMyService
{
public string HelloJSON(string name)
{
return string.Format("Hello {0} in JSON", name);
}
public List<Employee> GetEmployees()
{
using (DBEntities ctx = new DBEntities())
{
List<Employee> emp = new List<Employee>();
emp = (from e in ctx.Employee select e).ToList();
return emp;
}
}
}
When I call the first method I get something like "Hello pepe in JSON", that's ok.
When I call the second method and set a breakpoint on line "return emp;" I get the list of the employees(there are 6 records from the database), but in IE I get this:
Internet Explorer cannot display the webpage
and testing in Firefox all I get is a blank page with a blank body, no HTML, no data and no errors.
I think WCF can't serialize my default EF4 entities.
EDIT:
My final solution was something(not exactly) like this:
static string SerializeJSON<T>(T obj) {
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj); }
EF entities cannot be serialized by default you must add code generation to them.
Refer to this article on how to create Serializable entities.
called Self Tracking entities
The best way would be to enable RIA Services and expose JSON Endpoint, it does everything correctly.
http://blogs.msdn.com/b/davrous/archive/2010/12/14/how-to-open-a-wcf-ria-services-application-to-other-type-of-clients-the-json-endpoint-4-5.aspx
http://channel9.msdn.com/Shows/SilverlightTV/Silverlight-TV-26-Exposing-SOAP-OData-and-JSON-Endpoints-for-RIA-Services
I would like to create some sort of authentication attribute and attach it to various OperationContracts. Inside this attribute, it would check for an authentication token and make sure its still valid before the OperationContract is run.
What's the best way to implement this on the .net platform? Does wcf have any special attributes that already do this type of functionality? What I'm picturing is something similar to the attributes you can attach to MVC controllers that will perform operations before actions are run.
In case it's relevant, I am using WCF to create SOAP web services that will be consumed by clients on various platforms that support SOAP.. not just WCF clients
Here's some code to clarify what I'm trying to do:
interface:
[ServiceContract]
public interface IService
{
[OperationContract]
string ValidateUser(string username, string password);
[OperationContract]
string GetDataAndAuthInCode(string authtoken);
[MyAuthorizationAttribute]
[OperationContract]
string GetDataAndAuthWithAttribute(string authtoken);
}
implementation:
public class Service : IService
{
public string ValidateUser(string username, string password)
{
if (!Membership.ValidateUser(username, password))
throw new Exception("invalid user...");
else
return GenerateAuthToken(username);
}
public string GetDataAndAuthInCode(string authtoken)
{
if (!IsAuthTokenValid(authtoken))
throw new Exception("Auth token invalid expired");
else
return GetData();
}
public string GetDataAndAuthWithAttribute(string authtoken)
{
return GetData();
}
}
Looks like this is what I'm looking for.. "Custom Behaviors":
http://msdn.microsoft.com/en-us/magazine/cc163302.aspx#S7
I have written a WCF REST Service as follows
namespace UserService
{
// TODO: Modify the service behavior settings (instancing, concurrency etc) based on the service's requirements. Use ConcurrencyMode.Multiple if your service implementation
// is thread-safe.
// TODO: Please set IncludeExceptionDetailInFaults to false in production environments
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
public class Service
{
UserManager userManager = new UserManager();
[OperationContract]
[WebGet(UriTemplate = "{userName}")]
[WebHelp(Comment = "Gets an user object given the username")]
public User GetUser(string userName)
{
return userManager.Read(userName);
}
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "", RequestFormat=WebMessageFormat.Xml, ResponseFormat=WebMessageFormat.Xml, BodyStyle=WebMessageBodyStyle.Bare)]
[WebHelp(Comment = "Creates an User")]
public void CreateUser(User user)
{
userManager.Create(user);
}
}
}
I am accessing this from my ASP.NET application as follows.
HttpClient client = new HttpClient();
HttpContent content = null;
DiscussionForum.Library.User user = new User();
user.UserEmailAddress = emailAddressTextBox.Text;
user.UserName = userNameTextBox.Text;
user.UserPassword = passwordTextBox.Text;
content = HttpContentExtensions.CreateXmlSerializable<DiscussionForum.Library.User>(user);
content.LoadIntoBuffer();
HttpResponseMessage response = client.Post(new Uri("http://localhost/UserService/Service.svc"),"application/xml", content);
Response.Write(response.StatusCode.ToString());
I am getting a Badrequest 400 in the status code on the client side.
Am I missing something?
Well, one thing I immediately see is that your service uses the DataContractSerializer and your client uses the XmlSerializer, and so the XML representations of the "User" type probably aren't the same.
Either use the [XmlSerializerFormat] attribute on the service, or use HttpContentExtensions.CreateDataContract on the client (but not both of course :)
But I'm not 100% sure that this is your problem (or the only problem)... If it's not, reply here and I can help with some debugging tips.